@apollo/federation-internals 2.0.0-preview.9 → 2.0.2-alpha.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/CHANGELOG.md +34 -0
- package/dist/coreSpec.d.ts +2 -1
- package/dist/coreSpec.d.ts.map +1 -1
- package/dist/coreSpec.js +37 -11
- package/dist/coreSpec.js.map +1 -1
- package/dist/definitions.d.ts +20 -8
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +102 -62
- package/dist/definitions.js.map +1 -1
- package/dist/directiveAndTypeSpecification.d.ts.map +1 -1
- package/dist/directiveAndTypeSpecification.js +10 -1
- package/dist/directiveAndTypeSpecification.js.map +1 -1
- package/dist/error.d.ts +10 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +29 -9
- package/dist/error.js.map +1 -1
- package/dist/extractSubgraphsFromSupergraph.js +1 -1
- package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
- package/dist/federation.d.ts +4 -1
- package/dist/federation.d.ts.map +1 -1
- package/dist/federation.js +48 -26
- package/dist/federation.js.map +1 -1
- package/dist/federationSpec.js +1 -1
- package/dist/federationSpec.js.map +1 -1
- package/dist/genErrorCodeDoc.js +12 -6
- package/dist/genErrorCodeDoc.js.map +1 -1
- package/dist/inaccessibleSpec.d.ts +9 -4
- package/dist/inaccessibleSpec.d.ts.map +1 -1
- package/dist/inaccessibleSpec.js +625 -32
- package/dist/inaccessibleSpec.js.map +1 -1
- package/dist/joinSpec.d.ts +2 -1
- package/dist/joinSpec.d.ts.map +1 -1
- package/dist/joinSpec.js +3 -0
- package/dist/joinSpec.js.map +1 -1
- package/dist/operations.d.ts +20 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +52 -1
- package/dist/operations.js.map +1 -1
- package/dist/precompute.d.ts.map +1 -1
- package/dist/precompute.js +2 -2
- package/dist/precompute.js.map +1 -1
- package/dist/schemaUpgrader.d.ts +8 -1
- package/dist/schemaUpgrader.d.ts.map +1 -1
- package/dist/schemaUpgrader.js +56 -6
- package/dist/schemaUpgrader.js.map +1 -1
- package/dist/supergraphs.d.ts.map +1 -1
- package/dist/supergraphs.js +1 -0
- package/dist/supergraphs.js.map +1 -1
- package/dist/validate.js +13 -7
- package/dist/validate.js.map +1 -1
- package/dist/values.d.ts +2 -2
- package/dist/values.d.ts.map +1 -1
- package/dist/values.js +13 -11
- package/dist/values.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/coreSpec.test.ts +112 -0
- package/src/__tests__/removeInaccessibleElements.test.ts +2252 -177
- package/src/__tests__/schemaUpgrader.test.ts +38 -0
- package/src/__tests__/subgraphValidation.test.ts +96 -5
- package/src/__tests__/values.test.ts +315 -3
- package/src/coreSpec.ts +74 -16
- package/src/definitions.ts +207 -87
- package/src/directiveAndTypeSpecification.ts +18 -1
- package/src/error.ts +69 -9
- package/src/extractSubgraphsFromSupergraph.ts +1 -1
- package/src/federation.ts +86 -26
- package/src/federationSpec.ts +2 -2
- package/src/genErrorCodeDoc.ts +13 -7
- package/src/inaccessibleSpec.ts +978 -56
- package/src/joinSpec.ts +5 -1
- package/src/operations.ts +68 -2
- package/src/precompute.ts +2 -4
- package/src/schemaUpgrader.ts +70 -6
- package/src/supergraphs.ts +1 -0
- package/src/validate.ts +20 -9
- package/src/values.ts +39 -12
- package/tsconfig.test.tsbuildinfo +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,80 +1,124 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ArgumentDefinition,
|
|
3
|
+
errorCauses,
|
|
4
|
+
FieldDefinition,
|
|
5
|
+
InterfaceType,
|
|
6
|
+
ObjectType,
|
|
7
|
+
UnionType,
|
|
8
|
+
} from "../definitions";
|
|
9
|
+
import { buildSchema } from "../buildSchema";
|
|
10
|
+
import { removeInaccessibleElements } from "../inaccessibleSpec";
|
|
1
11
|
import { GraphQLErrorExt } from "@apollo/core-schema/dist/error";
|
|
2
|
-
import {
|
|
3
|
-
import { buildSchema } from '../buildSchema';
|
|
4
|
-
import { removeInaccessibleElements } from '../inaccessibleSpec';
|
|
12
|
+
import { GraphQLError } from "graphql";
|
|
5
13
|
|
|
6
|
-
describe(
|
|
7
|
-
|
|
14
|
+
describe("removeInaccessibleElements", () => {
|
|
15
|
+
const INACCESSIBLE_V02_HEADER = `
|
|
16
|
+
directive @core(feature: String!, as: String, for: core__Purpose) repeatable on SCHEMA
|
|
17
|
+
|
|
18
|
+
enum core__Purpose {
|
|
19
|
+
EXECUTION
|
|
20
|
+
SECURITY
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
24
|
+
|
|
25
|
+
schema
|
|
26
|
+
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
27
|
+
@core(feature: "https://specs.apollo.dev/inaccessible/v0.2")
|
|
28
|
+
{
|
|
29
|
+
query: Query
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
function getCauses(e: unknown): GraphQLError[] {
|
|
34
|
+
expect(e instanceof GraphQLErrorExt).toBeTruthy();
|
|
35
|
+
const causes = errorCauses(e as Error);
|
|
36
|
+
expect(causes).toBeDefined();
|
|
37
|
+
expect(Array.isArray(causes)).toBeTruthy();
|
|
38
|
+
for (const cause of causes!) {
|
|
39
|
+
expect(cause instanceof GraphQLError).toBeTruthy();
|
|
40
|
+
}
|
|
41
|
+
return causes!;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function expectErrors(expectedCauseCount: number, f: () => void): string[] {
|
|
45
|
+
let error: unknown = undefined;
|
|
46
|
+
try {
|
|
47
|
+
f();
|
|
48
|
+
} catch (e) {
|
|
49
|
+
error = e;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
expect(error).toBeDefined();
|
|
53
|
+
const causes = getCauses(error);
|
|
54
|
+
expect(causes).toHaveLength(expectedCauseCount);
|
|
55
|
+
const messages = causes.map((cause) => cause.message);
|
|
56
|
+
for (const message of messages) {
|
|
57
|
+
expect(typeof message === "string").toBeTruthy();
|
|
58
|
+
}
|
|
59
|
+
messages.sort();
|
|
60
|
+
return messages;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
it(`succeeds for no inaccessible spec`, () => {
|
|
8
64
|
const schema = buildSchema(`
|
|
9
65
|
directive @core(feature: String!, as: String, for: core__Purpose) repeatable on SCHEMA
|
|
10
66
|
|
|
11
|
-
|
|
67
|
+
enum core__Purpose {
|
|
68
|
+
EXECUTION
|
|
69
|
+
SECURITY
|
|
70
|
+
}
|
|
12
71
|
|
|
13
72
|
schema
|
|
14
73
|
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
15
|
-
@core(feature: "https://specs.apollo.dev/inaccessible/v0.1")
|
|
16
74
|
{
|
|
17
75
|
query: Query
|
|
18
76
|
}
|
|
19
77
|
|
|
20
|
-
enum core__Purpose {
|
|
21
|
-
EXECUTION
|
|
22
|
-
SECURITY
|
|
23
|
-
}
|
|
24
|
-
|
|
25
78
|
type Query {
|
|
26
79
|
someField: String
|
|
27
|
-
privateField: String @inaccessible
|
|
28
80
|
}
|
|
29
81
|
`);
|
|
30
82
|
|
|
31
83
|
removeInaccessibleElements(schema);
|
|
32
|
-
|
|
33
|
-
const queryType = schema.schemaDefinition.rootType('query')!;
|
|
34
|
-
|
|
35
|
-
expect(queryType.field('someField')).toBeDefined();
|
|
36
|
-
expect(queryType.field('privateField')).toBeUndefined();
|
|
84
|
+
schema.validate();
|
|
37
85
|
});
|
|
38
86
|
|
|
39
|
-
it(`
|
|
87
|
+
it(`doesn't affect non-core @inaccessible`, () => {
|
|
40
88
|
const schema = buildSchema(`
|
|
41
89
|
directive @core(feature: String!, as: String, for: core__Purpose) repeatable on SCHEMA
|
|
42
90
|
|
|
43
|
-
|
|
91
|
+
enum core__Purpose {
|
|
92
|
+
EXECUTION
|
|
93
|
+
SECURITY
|
|
94
|
+
}
|
|
44
95
|
|
|
45
96
|
schema
|
|
46
97
|
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
47
|
-
@core(feature: "https://specs.apollo.dev/inaccessible/v0.1")
|
|
48
98
|
{
|
|
49
99
|
query: Query
|
|
50
100
|
}
|
|
51
101
|
|
|
52
|
-
enum core__Purpose {
|
|
53
|
-
EXECUTION
|
|
54
|
-
SECURITY
|
|
55
|
-
}
|
|
56
|
-
|
|
57
102
|
type Query {
|
|
58
|
-
|
|
103
|
+
someField: String @inaccessible
|
|
59
104
|
}
|
|
60
105
|
|
|
61
|
-
|
|
62
|
-
someField: String
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
union Bar = Foo
|
|
106
|
+
directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
66
107
|
`);
|
|
67
108
|
|
|
68
109
|
removeInaccessibleElements(schema);
|
|
69
|
-
|
|
70
|
-
expect(schema.
|
|
110
|
+
schema.validate();
|
|
111
|
+
expect(schema.elementByCoordinate("Query.someField")).toBeDefined();
|
|
71
112
|
});
|
|
72
113
|
|
|
73
|
-
it(`
|
|
114
|
+
it(`fails for no @inaccessible definition`, () => {
|
|
74
115
|
const schema = buildSchema(`
|
|
75
116
|
directive @core(feature: String!, as: String, for: core__Purpose) repeatable on SCHEMA
|
|
76
117
|
|
|
77
|
-
|
|
118
|
+
enum core__Purpose {
|
|
119
|
+
EXECUTION
|
|
120
|
+
SECURITY
|
|
121
|
+
}
|
|
78
122
|
|
|
79
123
|
schema
|
|
80
124
|
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
@@ -83,269 +127,2300 @@ describe('removeInaccessibleElements', () => {
|
|
|
83
127
|
query: Query
|
|
84
128
|
}
|
|
85
129
|
|
|
130
|
+
type Query {
|
|
131
|
+
someField: String
|
|
132
|
+
}
|
|
133
|
+
`);
|
|
134
|
+
|
|
135
|
+
const errorMessages = expectErrors(1, () => {
|
|
136
|
+
removeInaccessibleElements(schema);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
140
|
+
Array [
|
|
141
|
+
"Invalid schema: declares https://specs.apollo.dev/inaccessible/v0.1 spec but does not define a @inaccessible directive.",
|
|
142
|
+
]
|
|
143
|
+
`);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it(`fails for incompatible @inaccessible definition`, () => {
|
|
147
|
+
const schema = buildSchema(`
|
|
148
|
+
directive @core(feature: String!, as: String, for: core__Purpose) repeatable on SCHEMA
|
|
149
|
+
|
|
86
150
|
enum core__Purpose {
|
|
87
151
|
EXECUTION
|
|
88
152
|
SECURITY
|
|
89
153
|
}
|
|
90
154
|
|
|
91
|
-
|
|
92
|
-
fooField: Foo @inaccessible
|
|
93
|
-
}
|
|
155
|
+
directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
94
156
|
|
|
95
|
-
|
|
96
|
-
|
|
157
|
+
schema
|
|
158
|
+
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
159
|
+
@core(feature: "https://specs.apollo.dev/inaccessible/v0.1")
|
|
160
|
+
{
|
|
161
|
+
query: Query
|
|
97
162
|
}
|
|
98
163
|
|
|
99
|
-
type
|
|
164
|
+
type Query {
|
|
100
165
|
someField: String
|
|
101
166
|
}
|
|
102
167
|
`);
|
|
103
168
|
|
|
104
|
-
|
|
169
|
+
const errorMessages = expectErrors(1, () => {
|
|
170
|
+
removeInaccessibleElements(schema);
|
|
171
|
+
});
|
|
105
172
|
|
|
106
|
-
expect(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
173
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
174
|
+
Array [
|
|
175
|
+
"Found invalid @inaccessible directive definition. Please ensure the directive definition in your schema's definitions matches the following:
|
|
176
|
+
directive @inaccessible on FIELD_DEFINITION | INTERFACE | OBJECT | UNION",
|
|
177
|
+
]
|
|
178
|
+
`);
|
|
111
179
|
});
|
|
112
180
|
|
|
113
|
-
it(`
|
|
181
|
+
it(`handles renames of @inaccessible via core "as"`, () => {
|
|
114
182
|
const schema = buildSchema(`
|
|
115
183
|
directive @core(feature: String!, as: String, for: core__Purpose) repeatable on SCHEMA
|
|
116
184
|
|
|
117
|
-
|
|
185
|
+
enum core__Purpose {
|
|
186
|
+
EXECUTION
|
|
187
|
+
SECURITY
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
directive @foo on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
118
191
|
|
|
119
192
|
schema
|
|
120
193
|
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
121
|
-
@core(feature: "https://specs.apollo.dev/inaccessible/v0.
|
|
194
|
+
@core(feature: "https://specs.apollo.dev/inaccessible/v0.2", as: "foo")
|
|
122
195
|
{
|
|
123
196
|
query: Query
|
|
124
197
|
}
|
|
125
198
|
|
|
126
|
-
|
|
199
|
+
type Query {
|
|
200
|
+
someField: Bar @inaccessible
|
|
201
|
+
privateField: String @foo
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
scalar Bar
|
|
205
|
+
|
|
206
|
+
directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
207
|
+
`);
|
|
208
|
+
|
|
209
|
+
removeInaccessibleElements(schema);
|
|
210
|
+
schema.validate();
|
|
211
|
+
expect(schema.elementByCoordinate("Query.someField")).toBeDefined();
|
|
212
|
+
expect(schema.elementByCoordinate("Query.privateField")).toBeUndefined();
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it(`handles renames of @inaccessible via import "as"`, () => {
|
|
216
|
+
const schema = buildSchema(`
|
|
217
|
+
directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA
|
|
218
|
+
|
|
219
|
+
enum link__Purpose {
|
|
127
220
|
EXECUTION
|
|
128
221
|
SECURITY
|
|
129
222
|
}
|
|
130
223
|
|
|
224
|
+
scalar link__Import
|
|
225
|
+
|
|
226
|
+
directive @foo on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
227
|
+
|
|
228
|
+
schema
|
|
229
|
+
@link(url: "https://specs.apollo.dev/link/v1.0")
|
|
230
|
+
@link(url: "https://specs.apollo.dev/inaccessible/v0.2", import: [{name: "@inaccessible", as: "@foo"}])
|
|
231
|
+
{
|
|
232
|
+
query: Query
|
|
233
|
+
}
|
|
234
|
+
|
|
131
235
|
type Query {
|
|
132
|
-
|
|
236
|
+
someField: Bar @inaccessible
|
|
237
|
+
privateField: String @foo
|
|
133
238
|
}
|
|
134
239
|
|
|
135
|
-
|
|
240
|
+
scalar Bar
|
|
241
|
+
|
|
242
|
+
directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
243
|
+
`);
|
|
244
|
+
|
|
245
|
+
removeInaccessibleElements(schema);
|
|
246
|
+
schema.validate();
|
|
247
|
+
expect(schema.elementByCoordinate("Query.someField")).toBeDefined();
|
|
248
|
+
expect(schema.elementByCoordinate("Query.privateField")).toBeUndefined();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it(`fails for @inaccessible built-ins`, () => {
|
|
252
|
+
const schema = buildSchema(`
|
|
253
|
+
${INACCESSIBLE_V02_HEADER}
|
|
136
254
|
|
|
137
|
-
type
|
|
255
|
+
type Query {
|
|
138
256
|
someField: String
|
|
139
257
|
}
|
|
140
258
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
259
|
+
# Built-in scalar
|
|
260
|
+
scalar String @inaccessible
|
|
261
|
+
|
|
262
|
+
# Built-in directive
|
|
263
|
+
directive @deprecated(
|
|
264
|
+
reason: String = "No longer supported" @inaccessible
|
|
265
|
+
) on FIELD_DEFINITION | ENUM_VALUE
|
|
144
266
|
`);
|
|
145
267
|
|
|
146
|
-
|
|
268
|
+
const errorMessages = expectErrors(2, () => {
|
|
269
|
+
removeInaccessibleElements(schema);
|
|
270
|
+
});
|
|
147
271
|
|
|
148
|
-
expect(
|
|
149
|
-
|
|
150
|
-
|
|
272
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
273
|
+
Array [
|
|
274
|
+
"Built-in directive \\"@deprecated\\" cannot use @inaccessible.",
|
|
275
|
+
"Built-in type \\"String\\" cannot use @inaccessible.",
|
|
276
|
+
]
|
|
277
|
+
`);
|
|
151
278
|
});
|
|
152
279
|
|
|
153
|
-
it(`
|
|
280
|
+
it(`fails for @inaccessible core feature definitions`, () => {
|
|
154
281
|
const schema = buildSchema(`
|
|
155
|
-
directive @core(feature: String
|
|
282
|
+
directive @core(feature: String! @inaccessible, as: String, for: core__Purpose) repeatable on SCHEMA
|
|
283
|
+
|
|
284
|
+
enum core__Purpose {
|
|
285
|
+
EXECUTION @inaccessible
|
|
286
|
+
SECURITY
|
|
287
|
+
}
|
|
156
288
|
|
|
157
|
-
directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
|
|
289
|
+
directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
158
290
|
|
|
159
291
|
schema
|
|
160
292
|
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
161
|
-
@core(feature: "https://specs.apollo.dev/inaccessible/v0.
|
|
293
|
+
@core(feature: "https://specs.apollo.dev/inaccessible/v0.2")
|
|
294
|
+
@core(feature: "http://localhost/foo/v1.0")
|
|
162
295
|
{
|
|
163
296
|
query: Query
|
|
164
297
|
}
|
|
165
298
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
SECURITY
|
|
299
|
+
type Query {
|
|
300
|
+
someField: String!
|
|
169
301
|
}
|
|
170
302
|
|
|
171
|
-
|
|
172
|
-
|
|
303
|
+
# Object type
|
|
304
|
+
type foo__Object1 @inaccessible {
|
|
305
|
+
foo__Field: String!
|
|
173
306
|
}
|
|
174
307
|
|
|
175
|
-
|
|
176
|
-
|
|
308
|
+
# Object field
|
|
309
|
+
type foo__Object2 implements foo__Interface2 {
|
|
310
|
+
foo__Field: foo__Enum1! @inaccessible
|
|
177
311
|
}
|
|
178
312
|
|
|
179
|
-
|
|
180
|
-
|
|
313
|
+
# Object field argument
|
|
314
|
+
type foo__Object3 {
|
|
315
|
+
someField(someArg: foo__Enum1 @inaccessible): foo__Enum2!
|
|
316
|
+
}
|
|
181
317
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const causes = errorCauses(err);
|
|
187
|
-
expect(causes).toBeTruthy();
|
|
188
|
-
expect(err.causes).toHaveLength(1);
|
|
189
|
-
expect(err.causes[0].toString()).toMatch(
|
|
190
|
-
`Field "Query.fooField" returns @inaccessible type "Foo" without being marked @inaccessible itself.`
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
});
|
|
318
|
+
# Interface type
|
|
319
|
+
interface foo__Interface1 @inaccessible {
|
|
320
|
+
foo__Field: String!
|
|
321
|
+
}
|
|
194
322
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
323
|
+
# Interface field
|
|
324
|
+
interface foo__Interface2 {
|
|
325
|
+
foo__Field: foo__Enum1! @inaccessible
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
# Interface field argument
|
|
329
|
+
interface foo__Interface3 {
|
|
330
|
+
someField(someArg: foo__InputObject1 @inaccessible): foo__Enum2!
|
|
331
|
+
}
|
|
198
332
|
|
|
199
|
-
|
|
333
|
+
# Union type
|
|
334
|
+
union foo__Union @inaccessible = foo__Object1 | foo__Object2 | foo__Object3
|
|
200
335
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
{
|
|
205
|
-
query: Query
|
|
336
|
+
# Input object type
|
|
337
|
+
input foo__InputObject1 @inaccessible {
|
|
338
|
+
someField: foo__Enum1
|
|
206
339
|
}
|
|
207
340
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
341
|
+
# Input object field
|
|
342
|
+
input foo__InputObject2 {
|
|
343
|
+
someField: foo__Scalar @inaccessible
|
|
211
344
|
}
|
|
212
345
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
346
|
+
# Enum type
|
|
347
|
+
enum foo__Enum1 @inaccessible {
|
|
348
|
+
someValue
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
# Enum value
|
|
352
|
+
enum foo__Enum2 {
|
|
353
|
+
someValue @inaccessible
|
|
216
354
|
}
|
|
217
355
|
|
|
218
|
-
|
|
356
|
+
# Scalar type
|
|
357
|
+
scalar foo__Scalar @inaccessible
|
|
358
|
+
|
|
359
|
+
# Directive argument
|
|
360
|
+
directive @foo(arg: foo__InputObject2 @inaccessible) repeatable on OBJECT
|
|
361
|
+
`);
|
|
362
|
+
|
|
363
|
+
// 15 = 6 type kinds + 3 field kinds + 3 argument kinds + 1 enum value + 2 extras on special core elements
|
|
364
|
+
const errorMessages = expectErrors(15, () => {
|
|
365
|
+
removeInaccessibleElements(schema);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
369
|
+
Array [
|
|
370
|
+
"Core feature directive \\"@core\\" cannot use @inaccessible.",
|
|
371
|
+
"Core feature directive \\"@foo\\" cannot use @inaccessible.",
|
|
372
|
+
"Core feature type \\"core__Purpose\\" cannot use @inaccessible.",
|
|
373
|
+
"Core feature type \\"foo__Enum1\\" cannot use @inaccessible.",
|
|
374
|
+
"Core feature type \\"foo__Enum2\\" cannot use @inaccessible.",
|
|
375
|
+
"Core feature type \\"foo__InputObject1\\" cannot use @inaccessible.",
|
|
376
|
+
"Core feature type \\"foo__InputObject2\\" cannot use @inaccessible.",
|
|
377
|
+
"Core feature type \\"foo__Interface1\\" cannot use @inaccessible.",
|
|
378
|
+
"Core feature type \\"foo__Interface2\\" cannot use @inaccessible.",
|
|
379
|
+
"Core feature type \\"foo__Interface3\\" cannot use @inaccessible.",
|
|
380
|
+
"Core feature type \\"foo__Object1\\" cannot use @inaccessible.",
|
|
381
|
+
"Core feature type \\"foo__Object2\\" cannot use @inaccessible.",
|
|
382
|
+
"Core feature type \\"foo__Object3\\" cannot use @inaccessible.",
|
|
383
|
+
"Core feature type \\"foo__Scalar\\" cannot use @inaccessible.",
|
|
384
|
+
"Core feature type \\"foo__Union\\" cannot use @inaccessible.",
|
|
385
|
+
]
|
|
386
|
+
`);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it(`fails for @inaccessible directive definitions that aren't only executable`, () => {
|
|
390
|
+
const schema = buildSchema(`
|
|
391
|
+
${INACCESSIBLE_V02_HEADER}
|
|
392
|
+
|
|
393
|
+
type Query {
|
|
219
394
|
someField: String
|
|
220
395
|
}
|
|
221
396
|
|
|
222
|
-
|
|
397
|
+
directive @foo(arg1: String @inaccessible) repeatable on OBJECT
|
|
398
|
+
|
|
399
|
+
directive @bar(arg2: String, arg3: String @inaccessible) repeatable on SCHEMA | FIELD
|
|
223
400
|
`);
|
|
224
401
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
expect(err.causes[1].toString()).toMatch(
|
|
236
|
-
`Field "Query.fooderationField" returns @inaccessible type "Foo" without being marked @inaccessible itself.`
|
|
237
|
-
);
|
|
238
|
-
}
|
|
402
|
+
const errorMessages = expectErrors(2, () => {
|
|
403
|
+
removeInaccessibleElements(schema);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
407
|
+
Array [
|
|
408
|
+
"Directive \\"@bar\\" cannot use @inaccessible because it may be applied to these type-system locations: SCHEMA.",
|
|
409
|
+
"Directive \\"@foo\\" cannot use @inaccessible because it may be applied to these type-system locations: OBJECT.",
|
|
410
|
+
]
|
|
411
|
+
`);
|
|
239
412
|
});
|
|
240
413
|
|
|
241
|
-
it(`removes @inaccessible
|
|
414
|
+
it(`removes @inaccessible object types`, () => {
|
|
242
415
|
const schema = buildSchema(`
|
|
243
|
-
|
|
416
|
+
${INACCESSIBLE_V02_HEADER}
|
|
244
417
|
|
|
245
|
-
|
|
418
|
+
extend schema {
|
|
419
|
+
mutation: Mutation
|
|
420
|
+
subscription: Subscription
|
|
421
|
+
}
|
|
246
422
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
{
|
|
251
|
-
query: Query
|
|
423
|
+
# Non-inaccessible object type
|
|
424
|
+
type Query {
|
|
425
|
+
someField: String
|
|
252
426
|
}
|
|
253
427
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
428
|
+
# Inaccessible mutation types should be removed
|
|
429
|
+
type Mutation @inaccessible {
|
|
430
|
+
someObject: Object
|
|
257
431
|
}
|
|
258
432
|
|
|
259
|
-
|
|
260
|
-
|
|
433
|
+
# Inaccessible subscription types should be removed
|
|
434
|
+
type Subscription @inaccessible {
|
|
435
|
+
someField: String
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
# Inaccessible object type
|
|
439
|
+
type Object @inaccessible {
|
|
440
|
+
someField: String
|
|
261
441
|
}
|
|
262
442
|
|
|
263
|
-
type
|
|
443
|
+
# Inaccessible object type referenced by inaccessible object field
|
|
444
|
+
type Referencer1 implements Referencer3 {
|
|
264
445
|
someField: String
|
|
446
|
+
privatefield: Object! @inaccessible
|
|
265
447
|
}
|
|
448
|
+
|
|
449
|
+
# Inaccessible object type referenced by non-inaccessible object field
|
|
450
|
+
# with inaccessible parent
|
|
451
|
+
type Referencer2 implements Referencer4 @inaccessible {
|
|
452
|
+
privateField: [Object!]!
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
# Inaccessible object type referenced by inaccessible interface field
|
|
456
|
+
interface Referencer3 {
|
|
457
|
+
someField: String
|
|
458
|
+
privatefield: Object @inaccessible
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
# Inaccessible object type referenced by non-inaccessible interface field
|
|
462
|
+
# with inaccessible parent
|
|
463
|
+
interface Referencer4 @inaccessible {
|
|
464
|
+
privateField: [Object]
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
# Inaccessible object type referenced by union member with
|
|
468
|
+
# non-inaccessible siblings and parent
|
|
469
|
+
union Referencer5 = Query | Object
|
|
470
|
+
|
|
471
|
+
# Inaccessible object type referenced by union member with no siblings
|
|
472
|
+
# but with inaccessible parent
|
|
473
|
+
union Referencer6 @inaccessible = Object
|
|
266
474
|
`);
|
|
267
475
|
|
|
268
476
|
removeInaccessibleElements(schema);
|
|
477
|
+
schema.validate();
|
|
478
|
+
expect(schema.elementByCoordinate("Query")).toBeDefined();
|
|
479
|
+
expect(schema.elementByCoordinate("Mutation")).toBeUndefined();
|
|
480
|
+
expect(schema.elementByCoordinate("Subscription")).toBeUndefined();
|
|
481
|
+
expect(schema.elementByCoordinate("Object")).toBeUndefined();
|
|
482
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
483
|
+
expect(
|
|
484
|
+
schema.elementByCoordinate("Referencer1.privatefield")
|
|
485
|
+
).toBeUndefined();
|
|
486
|
+
expect(schema.elementByCoordinate("Referencer2")).toBeUndefined();
|
|
487
|
+
expect(schema.elementByCoordinate("Referencer3.someField")).toBeDefined();
|
|
488
|
+
expect(
|
|
489
|
+
schema.elementByCoordinate("Referencer3.privatefield")
|
|
490
|
+
).toBeUndefined();
|
|
491
|
+
expect(schema.elementByCoordinate("Referencer4")).toBeUndefined();
|
|
492
|
+
const unionType = schema.elementByCoordinate("Referencer5");
|
|
493
|
+
expect(unionType instanceof UnionType).toBeTruthy();
|
|
494
|
+
expect((unionType as UnionType).hasTypeMember("Query")).toBeTruthy();
|
|
495
|
+
expect((unionType as UnionType).hasTypeMember("Object")).toBeFalsy();
|
|
496
|
+
expect(schema.elementByCoordinate("Referencer6")).toBeUndefined();
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it(`fails to remove @inaccessible object types for breaking removals`, () => {
|
|
500
|
+
const schema = buildSchema(`
|
|
501
|
+
${INACCESSIBLE_V02_HEADER}
|
|
502
|
+
|
|
503
|
+
# Query types can't be inaccessible
|
|
504
|
+
type Query @inaccessible {
|
|
505
|
+
someField: String
|
|
506
|
+
}
|
|
269
507
|
|
|
270
|
-
|
|
271
|
-
|
|
508
|
+
# Inaccessible object type
|
|
509
|
+
type Object @inaccessible {
|
|
510
|
+
someField: String
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
# Inaccessible object type can't be referenced by object field in the API
|
|
514
|
+
# schema
|
|
515
|
+
type Referencer1 implements Referencer2 {
|
|
516
|
+
someField: Object!
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
# Inaccessible object type can't be referenced by interface field in the
|
|
520
|
+
# API schema
|
|
521
|
+
interface Referencer2 {
|
|
522
|
+
someField: Object
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
# Inaccessible object type can't be referenced by union member with a
|
|
526
|
+
# non-inaccessible parent and no non-inaccessible siblings
|
|
527
|
+
union Referencer3 = Object
|
|
528
|
+
`);
|
|
272
529
|
|
|
273
|
-
|
|
530
|
+
const errorMessages = expectErrors(4, () => {
|
|
531
|
+
removeInaccessibleElements(schema);
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
535
|
+
Array [
|
|
536
|
+
"Type \\"Object\\" is @inaccessible but is referenced by \\"Referencer1.someField\\", which is in the API schema.",
|
|
537
|
+
"Type \\"Object\\" is @inaccessible but is referenced by \\"Referencer2.someField\\", which is in the API schema.",
|
|
538
|
+
"Type \\"Query\\" is @inaccessible but is the root query type, which must be in the API schema.",
|
|
539
|
+
"Type \\"Referencer3\\" is in the API schema but all of its members are @inaccessible.",
|
|
540
|
+
]
|
|
541
|
+
`);
|
|
274
542
|
});
|
|
275
543
|
|
|
276
|
-
it(`removes @inaccessible
|
|
544
|
+
it(`removes @inaccessible interface types`, () => {
|
|
277
545
|
const schema = buildSchema(`
|
|
278
|
-
|
|
546
|
+
${INACCESSIBLE_V02_HEADER}
|
|
279
547
|
|
|
280
|
-
|
|
548
|
+
type Query {
|
|
549
|
+
someField: String
|
|
550
|
+
}
|
|
281
551
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
{
|
|
286
|
-
query: Query
|
|
287
|
-
mutation: Mutation
|
|
552
|
+
# Non-inaccessible interface type
|
|
553
|
+
interface VisibleInterface {
|
|
554
|
+
someField: String
|
|
288
555
|
}
|
|
289
556
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
557
|
+
# Inaccessible interface type
|
|
558
|
+
interface Interface @inaccessible {
|
|
559
|
+
someField: String
|
|
293
560
|
}
|
|
294
561
|
|
|
295
|
-
type
|
|
296
|
-
|
|
562
|
+
# Inaccessible interface type referenced by inaccessible object field
|
|
563
|
+
type Referencer1 implements Referencer3 {
|
|
564
|
+
someField: String
|
|
565
|
+
privatefield: Interface! @inaccessible
|
|
297
566
|
}
|
|
298
567
|
|
|
299
|
-
type
|
|
300
|
-
|
|
568
|
+
# Inaccessible interface type referenced by non-inaccessible object field
|
|
569
|
+
# with inaccessible parent
|
|
570
|
+
type Referencer2 implements Referencer4 @inaccessible {
|
|
571
|
+
privateField: [Interface!]!
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
# Inaccessible interface type referenced by inaccessible interface field
|
|
575
|
+
interface Referencer3 {
|
|
576
|
+
someField: String
|
|
577
|
+
privatefield: Interface @inaccessible
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
# Inaccessible interface type referenced by non-inaccessible interface
|
|
581
|
+
# field with inaccessible parent
|
|
582
|
+
interface Referencer4 @inaccessible {
|
|
583
|
+
privateField: [Interface]
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
# Inaccessible interface type referenced by object type implements
|
|
587
|
+
type Referencer5 implements VisibleInterface & Interface {
|
|
588
|
+
someField: String
|
|
301
589
|
}
|
|
302
590
|
|
|
303
|
-
type
|
|
591
|
+
# Inaccessible interface type referenced by interface type implements
|
|
592
|
+
interface Referencer6 implements VisibleInterface & Interface {
|
|
304
593
|
someField: String
|
|
305
594
|
}
|
|
306
595
|
`);
|
|
307
596
|
|
|
308
597
|
removeInaccessibleElements(schema);
|
|
309
|
-
|
|
310
|
-
expect(schema.
|
|
311
|
-
expect(schema.
|
|
598
|
+
schema.validate();
|
|
599
|
+
expect(schema.elementByCoordinate("VisibleInterface")).toBeDefined();
|
|
600
|
+
expect(schema.elementByCoordinate("Interface")).toBeUndefined();
|
|
601
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
602
|
+
expect(
|
|
603
|
+
schema.elementByCoordinate("Referencer1.privatefield")
|
|
604
|
+
).toBeUndefined();
|
|
605
|
+
expect(schema.elementByCoordinate("Referencer2")).toBeUndefined();
|
|
606
|
+
expect(schema.elementByCoordinate("Referencer3.someField")).toBeDefined();
|
|
607
|
+
expect(
|
|
608
|
+
schema.elementByCoordinate("Referencer3.privatefield")
|
|
609
|
+
).toBeUndefined();
|
|
610
|
+
expect(schema.elementByCoordinate("Referencer4")).toBeUndefined();
|
|
611
|
+
const objectType = schema.elementByCoordinate("Referencer5");
|
|
612
|
+
expect(objectType instanceof ObjectType).toBeTruthy();
|
|
613
|
+
expect(
|
|
614
|
+
(objectType as ObjectType).implementsInterface("VisibleInterface")
|
|
615
|
+
).toBeTruthy();
|
|
616
|
+
expect(
|
|
617
|
+
(objectType as ObjectType).implementsInterface("Interface")
|
|
618
|
+
).toBeFalsy();
|
|
619
|
+
const interfaceType = schema.elementByCoordinate("Referencer6");
|
|
620
|
+
expect(interfaceType instanceof InterfaceType).toBeTruthy();
|
|
621
|
+
expect(
|
|
622
|
+
(interfaceType as InterfaceType).implementsInterface("VisibleInterface")
|
|
623
|
+
).toBeTruthy();
|
|
624
|
+
expect(
|
|
625
|
+
(interfaceType as InterfaceType).implementsInterface("Interface")
|
|
626
|
+
).toBeFalsy();
|
|
312
627
|
});
|
|
313
628
|
|
|
314
|
-
it(`
|
|
629
|
+
it(`fails to remove @inaccessible interface types for breaking removals`, () => {
|
|
315
630
|
const schema = buildSchema(`
|
|
316
|
-
|
|
631
|
+
${INACCESSIBLE_V02_HEADER}
|
|
317
632
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
schema
|
|
321
|
-
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
322
|
-
@core(feature: "https://specs.apollo.dev/inaccessible/v0.1")
|
|
323
|
-
{
|
|
324
|
-
query: Query
|
|
325
|
-
subscription: Subscription
|
|
633
|
+
type Query {
|
|
634
|
+
someField: String
|
|
326
635
|
}
|
|
327
636
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
637
|
+
# Inaccessible interface type
|
|
638
|
+
interface Interface @inaccessible {
|
|
639
|
+
someField: String
|
|
331
640
|
}
|
|
332
641
|
|
|
333
|
-
type
|
|
334
|
-
|
|
642
|
+
# Inaccessible interface type can't be referenced by object field in the
|
|
643
|
+
# API schema
|
|
644
|
+
type Referencer1 implements Referencer2 {
|
|
645
|
+
someField: [Interface!]!
|
|
335
646
|
}
|
|
336
647
|
|
|
337
|
-
type
|
|
338
|
-
|
|
648
|
+
# Inaccessible interface type can't be referenced by interface field in
|
|
649
|
+
# the API schema
|
|
650
|
+
interface Referencer2 {
|
|
651
|
+
someField: [Interface]
|
|
339
652
|
}
|
|
653
|
+
`);
|
|
654
|
+
|
|
655
|
+
const errorMessages = expectErrors(2, () => {
|
|
656
|
+
removeInaccessibleElements(schema);
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
660
|
+
Array [
|
|
661
|
+
"Type \\"Interface\\" is @inaccessible but is referenced by \\"Referencer1.someField\\", which is in the API schema.",
|
|
662
|
+
"Type \\"Interface\\" is @inaccessible but is referenced by \\"Referencer2.someField\\", which is in the API schema.",
|
|
663
|
+
]
|
|
664
|
+
`);
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
it(`removes @inaccessible union types`, () => {
|
|
668
|
+
const schema = buildSchema(`
|
|
669
|
+
${INACCESSIBLE_V02_HEADER}
|
|
340
670
|
|
|
341
|
-
type
|
|
671
|
+
type Query {
|
|
342
672
|
someField: String
|
|
343
673
|
}
|
|
344
|
-
`);
|
|
345
674
|
|
|
346
|
-
|
|
675
|
+
# Non-inaccessible union type
|
|
676
|
+
union VisibleUnion = Query
|
|
347
677
|
|
|
348
|
-
|
|
349
|
-
|
|
678
|
+
# Inaccessible union type
|
|
679
|
+
union Union @inaccessible = Query
|
|
680
|
+
|
|
681
|
+
# Inaccessible union type referenced by inaccessible object field
|
|
682
|
+
type Referencer1 implements Referencer3 {
|
|
683
|
+
someField: String
|
|
684
|
+
privatefield: Union! @inaccessible
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
# Inaccessible union type referenced by non-inaccessible object field with
|
|
688
|
+
# inaccessible parent
|
|
689
|
+
type Referencer2 implements Referencer4 @inaccessible {
|
|
690
|
+
privateField: [Union!]!
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
# Inaccessible union type referenced by inaccessible interface field
|
|
694
|
+
interface Referencer3 {
|
|
695
|
+
someField: String
|
|
696
|
+
privatefield: Union @inaccessible
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
# Inaccessible union type referenced by non-inaccessible interface field
|
|
700
|
+
# with inaccessible parent
|
|
701
|
+
interface Referencer4 @inaccessible {
|
|
702
|
+
privateField: [Union]
|
|
703
|
+
}
|
|
704
|
+
`);
|
|
705
|
+
|
|
706
|
+
removeInaccessibleElements(schema);
|
|
707
|
+
schema.validate();
|
|
708
|
+
expect(schema.elementByCoordinate("VisibleUnion")).toBeDefined();
|
|
709
|
+
expect(schema.elementByCoordinate("Union")).toBeUndefined();
|
|
710
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
711
|
+
expect(
|
|
712
|
+
schema.elementByCoordinate("Referencer1.privatefield")
|
|
713
|
+
).toBeUndefined();
|
|
714
|
+
expect(schema.elementByCoordinate("Referencer2")).toBeUndefined();
|
|
715
|
+
expect(schema.elementByCoordinate("Referencer3.someField")).toBeDefined();
|
|
716
|
+
expect(
|
|
717
|
+
schema.elementByCoordinate("Referencer3.privatefield")
|
|
718
|
+
).toBeUndefined();
|
|
719
|
+
expect(schema.elementByCoordinate("Referencer4")).toBeUndefined();
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
it(`fails to remove @inaccessible union types for breaking removals`, () => {
|
|
723
|
+
const schema = buildSchema(`
|
|
724
|
+
${INACCESSIBLE_V02_HEADER}
|
|
725
|
+
|
|
726
|
+
type Query {
|
|
727
|
+
someField: String
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
# Inaccessible union type
|
|
731
|
+
union Union @inaccessible = Query
|
|
732
|
+
|
|
733
|
+
# Inaccessible union type can't be referenced by object field in the API
|
|
734
|
+
# schema
|
|
735
|
+
type Referencer1 implements Referencer2 {
|
|
736
|
+
someField: Union!
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
# Inaccessible union type can't be referenced by interface field in the
|
|
740
|
+
# API schema
|
|
741
|
+
interface Referencer2 {
|
|
742
|
+
someField: Union
|
|
743
|
+
}
|
|
744
|
+
`);
|
|
745
|
+
|
|
746
|
+
const errorMessages = expectErrors(2, () => {
|
|
747
|
+
removeInaccessibleElements(schema);
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
751
|
+
Array [
|
|
752
|
+
"Type \\"Union\\" is @inaccessible but is referenced by \\"Referencer1.someField\\", which is in the API schema.",
|
|
753
|
+
"Type \\"Union\\" is @inaccessible but is referenced by \\"Referencer2.someField\\", which is in the API schema.",
|
|
754
|
+
]
|
|
755
|
+
`);
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
it(`removes @inaccessible input object types`, () => {
|
|
759
|
+
const schema = buildSchema(`
|
|
760
|
+
${INACCESSIBLE_V02_HEADER}
|
|
761
|
+
|
|
762
|
+
type Query {
|
|
763
|
+
someField: String
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
# Non-inaccessible input object type
|
|
767
|
+
input VisibleInputObject {
|
|
768
|
+
someField: String
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
# Inaccessible input object type
|
|
772
|
+
input InputObject @inaccessible {
|
|
773
|
+
someField: String
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
# Inaccessible input object type referenced by inaccessible object field
|
|
777
|
+
# argument
|
|
778
|
+
type Referencer1 implements Referencer4 {
|
|
779
|
+
someField(privateArg: InputObject @inaccessible): String
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
# Inaccessible input object type referenced by non-inaccessible object
|
|
783
|
+
# field argument with inaccessible parent
|
|
784
|
+
type Referencer2 implements Referencer5 {
|
|
785
|
+
someField: String
|
|
786
|
+
privateField(privateArg: InputObject!): String @inaccessible
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
# Inaccessible input object type referenced by non-inaccessible object
|
|
790
|
+
# field argument with inaccessible grandparent
|
|
791
|
+
type Referencer3 implements Referencer6 @inaccessible {
|
|
792
|
+
privateField(privateArg: InputObject!): String
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
# Inaccessible input object type referenced by inaccessible interface
|
|
796
|
+
# field argument
|
|
797
|
+
interface Referencer4 {
|
|
798
|
+
someField(privateArg: InputObject @inaccessible): String
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
# Inaccessible input object type referenced by non-inaccessible interface
|
|
802
|
+
# field argument with inaccessible parent
|
|
803
|
+
interface Referencer5 {
|
|
804
|
+
someField: String
|
|
805
|
+
privateField(privateArg: InputObject!): String @inaccessible
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
# Inaccessible input object type referenced by non-inaccessible interface
|
|
809
|
+
# field argument with inaccessible grandparent
|
|
810
|
+
interface Referencer6 @inaccessible {
|
|
811
|
+
privateField(privateArg: InputObject!): String
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
# Inaccessible input object type referenced by inaccessible input object
|
|
815
|
+
# field
|
|
816
|
+
input Referencer7 {
|
|
817
|
+
someField: String
|
|
818
|
+
privateField: InputObject @inaccessible
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
# Inaccessible input object type referenced by non-inaccessible input
|
|
822
|
+
# object field with inaccessible parent
|
|
823
|
+
input Referencer8 @inaccessible {
|
|
824
|
+
privateField: InputObject!
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
# Inaccessible input object type referenced by inaccessible directive
|
|
828
|
+
# argument
|
|
829
|
+
directive @referencer9(privateArg: InputObject @inaccessible) on FIELD
|
|
830
|
+
`);
|
|
831
|
+
|
|
832
|
+
removeInaccessibleElements(schema);
|
|
833
|
+
schema.validate();
|
|
834
|
+
expect(schema.elementByCoordinate("VisibleInputObject")).toBeDefined();
|
|
835
|
+
expect(schema.elementByCoordinate("InputObject")).toBeUndefined();
|
|
836
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
837
|
+
expect(
|
|
838
|
+
schema.elementByCoordinate("Referencer1.someField(privateArg:)")
|
|
839
|
+
).toBeUndefined();
|
|
840
|
+
expect(schema.elementByCoordinate("Referencer2.someField")).toBeDefined();
|
|
841
|
+
expect(
|
|
842
|
+
schema.elementByCoordinate("Referencer2.privateField")
|
|
843
|
+
).toBeUndefined();
|
|
844
|
+
expect(schema.elementByCoordinate("Referencer3")).toBeUndefined();
|
|
845
|
+
expect(schema.elementByCoordinate("Referencer4.someField")).toBeDefined();
|
|
846
|
+
expect(
|
|
847
|
+
schema.elementByCoordinate("Referencer4.someField(privateArg:)")
|
|
848
|
+
).toBeUndefined();
|
|
849
|
+
expect(schema.elementByCoordinate("Referencer5.someField")).toBeDefined();
|
|
850
|
+
expect(
|
|
851
|
+
schema.elementByCoordinate("Referencer5.privateField")
|
|
852
|
+
).toBeUndefined();
|
|
853
|
+
expect(schema.elementByCoordinate("Referencer6")).toBeUndefined();
|
|
854
|
+
expect(schema.elementByCoordinate("Referencer7.someField")).toBeDefined();
|
|
855
|
+
expect(
|
|
856
|
+
schema.elementByCoordinate("Referencer7.privatefield")
|
|
857
|
+
).toBeUndefined();
|
|
858
|
+
expect(schema.elementByCoordinate("Referencer8")).toBeUndefined();
|
|
859
|
+
expect(schema.elementByCoordinate("@referencer9")).toBeDefined();
|
|
860
|
+
expect(
|
|
861
|
+
schema.elementByCoordinate("@referencer9(privateArg:)")
|
|
862
|
+
).toBeUndefined();
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
it(`fails to remove @inaccessible input object types for breaking removals`, () => {
|
|
866
|
+
const schema = buildSchema(`
|
|
867
|
+
${INACCESSIBLE_V02_HEADER}
|
|
868
|
+
|
|
869
|
+
type Query {
|
|
870
|
+
someField: String
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
# Inaccessible input object type
|
|
874
|
+
input InputObject @inaccessible {
|
|
875
|
+
someField: String
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
# Inaccessible input object type can't be referenced by object field
|
|
879
|
+
# argument in the API schema
|
|
880
|
+
type Referencer1 implements Referencer2 {
|
|
881
|
+
someField(someArg: InputObject): String
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
# Inaccessible input object type can't be referenced by interface field
|
|
885
|
+
# argument in the API schema
|
|
886
|
+
interface Referencer2 {
|
|
887
|
+
someField(someArg: InputObject): String
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
# Inaccessible input object type can't be referenced by input object field
|
|
891
|
+
# in the API schema
|
|
892
|
+
input Referencer3 {
|
|
893
|
+
someField: InputObject
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
# Inaccessible input object type can't be referenced by directive argument
|
|
897
|
+
# in the API schema
|
|
898
|
+
directive @referencer4(someArg: InputObject) on QUERY
|
|
899
|
+
`);
|
|
900
|
+
|
|
901
|
+
const errorMessages = expectErrors(4, () => {
|
|
902
|
+
removeInaccessibleElements(schema);
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
906
|
+
Array [
|
|
907
|
+
"Type \\"InputObject\\" is @inaccessible but is referenced by \\"@referencer4(someArg:)\\", which is in the API schema.",
|
|
908
|
+
"Type \\"InputObject\\" is @inaccessible but is referenced by \\"Referencer1.someField(someArg:)\\", which is in the API schema.",
|
|
909
|
+
"Type \\"InputObject\\" is @inaccessible but is referenced by \\"Referencer2.someField(someArg:)\\", which is in the API schema.",
|
|
910
|
+
"Type \\"InputObject\\" is @inaccessible but is referenced by \\"Referencer3.someField\\", which is in the API schema.",
|
|
911
|
+
]
|
|
912
|
+
`);
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
it(`removes @inaccessible enum types`, () => {
|
|
916
|
+
const schema = buildSchema(`
|
|
917
|
+
${INACCESSIBLE_V02_HEADER}
|
|
918
|
+
|
|
919
|
+
type Query {
|
|
920
|
+
someField: String
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
# Non-inaccessible enum type
|
|
924
|
+
enum VisibleEnum {
|
|
925
|
+
SOME_VALUE
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
# Inaccessible enum type
|
|
929
|
+
enum Enum @inaccessible {
|
|
930
|
+
SOME_VALUE
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
# Inaccessible enum type referenced by inaccessible object field
|
|
934
|
+
type Referencer1 implements Referencer3 {
|
|
935
|
+
someField: String
|
|
936
|
+
privatefield: Enum! @inaccessible
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
# Inaccessible enum type referenced by non-inaccessible object field with
|
|
940
|
+
# inaccessible parent
|
|
941
|
+
type Referencer2 implements Referencer4 @inaccessible {
|
|
942
|
+
privateField: [Enum!]!
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
# Inaccessible enum type referenced by inaccessible interface field
|
|
946
|
+
interface Referencer3 {
|
|
947
|
+
someField: String
|
|
948
|
+
privatefield: Enum @inaccessible
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
# Inaccessible enum type referenced by non-inaccessible interface field
|
|
952
|
+
# with inaccessible parent
|
|
953
|
+
interface Referencer4 @inaccessible {
|
|
954
|
+
privateField: [Enum]
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
# Inaccessible enum type referenced by inaccessible object field argument
|
|
958
|
+
type Referencer5 implements Referencer8 {
|
|
959
|
+
someField(privateArg: Enum @inaccessible): String
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
# Inaccessible enum type referenced by non-inaccessible object field
|
|
963
|
+
# argument with inaccessible parent
|
|
964
|
+
type Referencer6 implements Referencer9 {
|
|
965
|
+
someField: String
|
|
966
|
+
privateField(privateArg: Enum!): String @inaccessible
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
# Inaccessible enum type referenced by non-inaccessible object field
|
|
970
|
+
# argument with inaccessible grandparent
|
|
971
|
+
type Referencer7 implements Referencer10 @inaccessible {
|
|
972
|
+
privateField(privateArg: Enum!): String
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
# Inaccessible enum type referenced by inaccessible interface field
|
|
976
|
+
# argument
|
|
977
|
+
interface Referencer8 {
|
|
978
|
+
someField(privateArg: Enum @inaccessible): String
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
# Inaccessible enum type referenced by non-inaccessible interface field
|
|
982
|
+
# argument with inaccessible parent
|
|
983
|
+
interface Referencer9 {
|
|
984
|
+
someField: String
|
|
985
|
+
privateField(privateArg: Enum!): String @inaccessible
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
# Inaccessible enum type referenced by non-inaccessible interface field
|
|
989
|
+
# argument with inaccessible grandparent
|
|
990
|
+
interface Referencer10 @inaccessible {
|
|
991
|
+
privateField(privateArg: Enum!): String
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
# Inaccessible enum type referenced by inaccessible input object field
|
|
995
|
+
input Referencer11 {
|
|
996
|
+
someField: String
|
|
997
|
+
privateField: Enum @inaccessible
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
# Inaccessible enum type referenced by non-inaccessible input object field
|
|
1001
|
+
# with inaccessible parent
|
|
1002
|
+
input Referencer12 @inaccessible {
|
|
1003
|
+
privateField: Enum!
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
# Inaccessible enum type referenced by inaccessible directive argument
|
|
1007
|
+
directive @referencer13(privateArg: Enum @inaccessible) on FRAGMENT_DEFINITION
|
|
1008
|
+
`);
|
|
1009
|
+
|
|
1010
|
+
removeInaccessibleElements(schema);
|
|
1011
|
+
schema.validate();
|
|
1012
|
+
expect(schema.elementByCoordinate("VisibleEnum")).toBeDefined();
|
|
1013
|
+
expect(schema.elementByCoordinate("Enum")).toBeUndefined();
|
|
1014
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
1015
|
+
expect(
|
|
1016
|
+
schema.elementByCoordinate("Referencer1.privatefield")
|
|
1017
|
+
).toBeUndefined();
|
|
1018
|
+
expect(schema.elementByCoordinate("Referencer2")).toBeUndefined();
|
|
1019
|
+
expect(schema.elementByCoordinate("Referencer3.someField")).toBeDefined();
|
|
1020
|
+
expect(
|
|
1021
|
+
schema.elementByCoordinate("Referencer3.privatefield")
|
|
1022
|
+
).toBeUndefined();
|
|
1023
|
+
expect(schema.elementByCoordinate("Referencer4")).toBeUndefined();
|
|
1024
|
+
expect(schema.elementByCoordinate("Referencer5.someField")).toBeDefined();
|
|
1025
|
+
expect(
|
|
1026
|
+
schema.elementByCoordinate("Referencer5.someField(privateArg:)")
|
|
1027
|
+
).toBeUndefined();
|
|
1028
|
+
expect(schema.elementByCoordinate("Referencer6.someField")).toBeDefined();
|
|
1029
|
+
expect(
|
|
1030
|
+
schema.elementByCoordinate("Referencer6.privateField")
|
|
1031
|
+
).toBeUndefined();
|
|
1032
|
+
expect(schema.elementByCoordinate("Referencer7")).toBeUndefined();
|
|
1033
|
+
expect(schema.elementByCoordinate("Referencer8.someField")).toBeDefined();
|
|
1034
|
+
expect(
|
|
1035
|
+
schema.elementByCoordinate("Referencer8.someField(privateArg:)")
|
|
1036
|
+
).toBeUndefined();
|
|
1037
|
+
expect(schema.elementByCoordinate("Referencer9.someField")).toBeDefined();
|
|
1038
|
+
expect(
|
|
1039
|
+
schema.elementByCoordinate("Referencer9.privateField")
|
|
1040
|
+
).toBeUndefined();
|
|
1041
|
+
expect(schema.elementByCoordinate("Referencer10")).toBeUndefined();
|
|
1042
|
+
expect(schema.elementByCoordinate("Referencer11.someField")).toBeDefined();
|
|
1043
|
+
expect(
|
|
1044
|
+
schema.elementByCoordinate("Referencer11.privatefield")
|
|
1045
|
+
).toBeUndefined();
|
|
1046
|
+
expect(schema.elementByCoordinate("Referencer12")).toBeUndefined();
|
|
1047
|
+
expect(schema.elementByCoordinate("@referencer13")).toBeDefined();
|
|
1048
|
+
expect(
|
|
1049
|
+
schema.elementByCoordinate("@referencer13(privateArg:)")
|
|
1050
|
+
).toBeUndefined();
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
it(`fails to remove @inaccessible enum types for breaking removals`, () => {
|
|
1054
|
+
const schema = buildSchema(`
|
|
1055
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1056
|
+
|
|
1057
|
+
type Query {
|
|
1058
|
+
someField: String
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
# Inaccessible enum type
|
|
1062
|
+
enum Enum @inaccessible {
|
|
1063
|
+
SOME_VALUE
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
# Inaccessible enum type can't be referenced by object field in the API
|
|
1067
|
+
# schema
|
|
1068
|
+
type Referencer1 implements Referencer2 {
|
|
1069
|
+
somefield: [Enum!]!
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
# Inaccessible enum type can't be referenced by interface field in the API
|
|
1073
|
+
# schema
|
|
1074
|
+
interface Referencer2 {
|
|
1075
|
+
somefield: [Enum]
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
# Inaccessible enum type can't be referenced by object field argument in
|
|
1079
|
+
# the API schema
|
|
1080
|
+
type Referencer3 implements Referencer4 {
|
|
1081
|
+
someField(someArg: Enum): String
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
# Inaccessible enum type can't be referenced by interface field argument
|
|
1085
|
+
# in the API schema
|
|
1086
|
+
interface Referencer4 {
|
|
1087
|
+
someField(someArg: Enum): String
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
# Inaccessible enum type can't be referenced by input object field in the
|
|
1091
|
+
# API schema
|
|
1092
|
+
input Referencer5 {
|
|
1093
|
+
someField: Enum
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
# Inaccessible enum type can't be referenced by directive argument in the
|
|
1097
|
+
# API schema
|
|
1098
|
+
directive @referencer6(someArg: Enum) on FRAGMENT_SPREAD
|
|
1099
|
+
`);
|
|
1100
|
+
|
|
1101
|
+
const errorMessages = expectErrors(6, () => {
|
|
1102
|
+
removeInaccessibleElements(schema);
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
1106
|
+
Array [
|
|
1107
|
+
"Type \\"Enum\\" is @inaccessible but is referenced by \\"@referencer6(someArg:)\\", which is in the API schema.",
|
|
1108
|
+
"Type \\"Enum\\" is @inaccessible but is referenced by \\"Referencer1.somefield\\", which is in the API schema.",
|
|
1109
|
+
"Type \\"Enum\\" is @inaccessible but is referenced by \\"Referencer2.somefield\\", which is in the API schema.",
|
|
1110
|
+
"Type \\"Enum\\" is @inaccessible but is referenced by \\"Referencer3.someField(someArg:)\\", which is in the API schema.",
|
|
1111
|
+
"Type \\"Enum\\" is @inaccessible but is referenced by \\"Referencer4.someField(someArg:)\\", which is in the API schema.",
|
|
1112
|
+
"Type \\"Enum\\" is @inaccessible but is referenced by \\"Referencer5.someField\\", which is in the API schema.",
|
|
1113
|
+
]
|
|
1114
|
+
`);
|
|
1115
|
+
});
|
|
1116
|
+
|
|
1117
|
+
it(`removes @inaccessible scalar types`, () => {
|
|
1118
|
+
const schema = buildSchema(`
|
|
1119
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1120
|
+
|
|
1121
|
+
type Query {
|
|
1122
|
+
someField: String
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
# Non-inaccessible scalar type
|
|
1126
|
+
scalar VisibleScalar
|
|
1127
|
+
|
|
1128
|
+
# Inaccessible scalar type
|
|
1129
|
+
scalar Scalar @inaccessible
|
|
1130
|
+
|
|
1131
|
+
# Inaccessible scalar type referenced by inaccessible object field
|
|
1132
|
+
type Referencer1 implements Referencer3 {
|
|
1133
|
+
someField: String
|
|
1134
|
+
privatefield: Scalar! @inaccessible
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
# Inaccessible scalar type referenced by non-inaccessible object field
|
|
1138
|
+
# with inaccessible parent
|
|
1139
|
+
type Referencer2 implements Referencer4 @inaccessible {
|
|
1140
|
+
privateField: [Scalar!]!
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
# Inaccessible scalar type referenced by inaccessible interface field
|
|
1144
|
+
interface Referencer3 {
|
|
1145
|
+
someField: String
|
|
1146
|
+
privatefield: Scalar @inaccessible
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
# Inaccessible scalar type referenced by non-inaccessible interface field
|
|
1150
|
+
# with inaccessible parent
|
|
1151
|
+
interface Referencer4 @inaccessible {
|
|
1152
|
+
privateField: [Scalar]
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
# Inaccessible scalar type referenced by inaccessible object field
|
|
1156
|
+
# argument
|
|
1157
|
+
type Referencer5 implements Referencer8 {
|
|
1158
|
+
someField(privateArg: Scalar @inaccessible): String
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
# Inaccessible scalar type referenced by non-inaccessible object field
|
|
1162
|
+
# argument with inaccessible parent
|
|
1163
|
+
type Referencer6 implements Referencer9 {
|
|
1164
|
+
someField: String
|
|
1165
|
+
privateField(privateArg: Scalar!): String @inaccessible
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
# Inaccessible scalar type referenced by non-inaccessible object field
|
|
1169
|
+
# argument with inaccessible grandparent
|
|
1170
|
+
type Referencer7 implements Referencer10 @inaccessible {
|
|
1171
|
+
privateField(privateArg: Scalar!): String
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
# Inaccessible scalar type referenced by inaccessible interface field
|
|
1175
|
+
# argument
|
|
1176
|
+
interface Referencer8 {
|
|
1177
|
+
someField(privateArg: Scalar @inaccessible): String
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
# Inaccessible scalar type referenced by non-inaccessible interface field
|
|
1181
|
+
# argument with inaccessible parent
|
|
1182
|
+
interface Referencer9 {
|
|
1183
|
+
someField: String
|
|
1184
|
+
privateField(privateArg: Scalar!): String @inaccessible
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
# Inaccessible scalar type referenced by non-inaccessible interface field
|
|
1188
|
+
# argument with inaccessible grandparent
|
|
1189
|
+
interface Referencer10 @inaccessible {
|
|
1190
|
+
privateField(privateArg: Scalar!): String
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
# Inaccessible scalar type referenced by inaccessible input object field
|
|
1194
|
+
input Referencer11 {
|
|
1195
|
+
someField: String
|
|
1196
|
+
privateField: Scalar @inaccessible
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
# Inaccessible scalar type referenced by non-inaccessible input object
|
|
1200
|
+
# field with inaccessible parent
|
|
1201
|
+
input Referencer12 @inaccessible {
|
|
1202
|
+
privateField: Scalar!
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
# Inaccessible scalar type referenced by inaccessible directive argument
|
|
1206
|
+
directive @referencer13(privateArg: Scalar @inaccessible) on INLINE_FRAGMENT
|
|
1207
|
+
`);
|
|
1208
|
+
|
|
1209
|
+
removeInaccessibleElements(schema);
|
|
1210
|
+
schema.validate();
|
|
1211
|
+
expect(schema.elementByCoordinate("VisibleScalar")).toBeDefined();
|
|
1212
|
+
expect(schema.elementByCoordinate("Scalar")).toBeUndefined();
|
|
1213
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
1214
|
+
expect(
|
|
1215
|
+
schema.elementByCoordinate("Referencer1.privatefield")
|
|
1216
|
+
).toBeUndefined();
|
|
1217
|
+
expect(schema.elementByCoordinate("Referencer2")).toBeUndefined();
|
|
1218
|
+
expect(schema.elementByCoordinate("Referencer3.someField")).toBeDefined();
|
|
1219
|
+
expect(
|
|
1220
|
+
schema.elementByCoordinate("Referencer3.privatefield")
|
|
1221
|
+
).toBeUndefined();
|
|
1222
|
+
expect(schema.elementByCoordinate("Referencer4")).toBeUndefined();
|
|
1223
|
+
expect(schema.elementByCoordinate("Referencer5.someField")).toBeDefined();
|
|
1224
|
+
expect(
|
|
1225
|
+
schema.elementByCoordinate("Referencer5.someField(privateArg:)")
|
|
1226
|
+
).toBeUndefined();
|
|
1227
|
+
expect(schema.elementByCoordinate("Referencer6.someField")).toBeDefined();
|
|
1228
|
+
expect(
|
|
1229
|
+
schema.elementByCoordinate("Referencer6.privateField")
|
|
1230
|
+
).toBeUndefined();
|
|
1231
|
+
expect(schema.elementByCoordinate("Referencer7")).toBeUndefined();
|
|
1232
|
+
expect(schema.elementByCoordinate("Referencer8.someField")).toBeDefined();
|
|
1233
|
+
expect(
|
|
1234
|
+
schema.elementByCoordinate("Referencer8.someField(privateArg:)")
|
|
1235
|
+
).toBeUndefined();
|
|
1236
|
+
expect(schema.elementByCoordinate("Referencer9.someField")).toBeDefined();
|
|
1237
|
+
expect(
|
|
1238
|
+
schema.elementByCoordinate("Referencer9.privateField")
|
|
1239
|
+
).toBeUndefined();
|
|
1240
|
+
expect(schema.elementByCoordinate("Referencer10")).toBeUndefined();
|
|
1241
|
+
expect(schema.elementByCoordinate("Referencer11.someField")).toBeDefined();
|
|
1242
|
+
expect(
|
|
1243
|
+
schema.elementByCoordinate("Referencer11.privatefield")
|
|
1244
|
+
).toBeUndefined();
|
|
1245
|
+
expect(schema.elementByCoordinate("Referencer12")).toBeUndefined();
|
|
1246
|
+
expect(schema.elementByCoordinate("@referencer13")).toBeDefined();
|
|
1247
|
+
expect(
|
|
1248
|
+
schema.elementByCoordinate("@referencer13(privateArg:)")
|
|
1249
|
+
).toBeUndefined();
|
|
1250
|
+
});
|
|
1251
|
+
|
|
1252
|
+
it(`fails to remove @inaccessible scalar types for breaking removals`, () => {
|
|
1253
|
+
const schema = buildSchema(`
|
|
1254
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1255
|
+
|
|
1256
|
+
type Query {
|
|
1257
|
+
someField: String
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
# Inaccessible scalar type
|
|
1261
|
+
scalar Scalar @inaccessible
|
|
1262
|
+
|
|
1263
|
+
# Inaccessible scalar type can't be referenced by object field in the API
|
|
1264
|
+
# schema
|
|
1265
|
+
type Referencer1 implements Referencer2 {
|
|
1266
|
+
somefield: [[Scalar!]!]!
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
# Inaccessible scalar type can't be referenced by interface field in the
|
|
1270
|
+
# API schema
|
|
1271
|
+
interface Referencer2 {
|
|
1272
|
+
somefield: [[Scalar]]
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
# Inaccessible scalar type can't be referenced by object field argument in
|
|
1276
|
+
# the API schema
|
|
1277
|
+
type Referencer3 implements Referencer4 {
|
|
1278
|
+
someField(someArg: Scalar): String
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
# Inaccessible scalar type can't be referenced by interface field argument
|
|
1282
|
+
# in the API schema
|
|
1283
|
+
interface Referencer4 {
|
|
1284
|
+
someField(someArg: Scalar): String
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
# Inaccessible scalar type can't be referenced by input object field in
|
|
1288
|
+
# the API schema
|
|
1289
|
+
input Referencer5 {
|
|
1290
|
+
someField: Scalar
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
# Inaccessible scalar type can't be referenced by directive argument in
|
|
1294
|
+
# the API schema
|
|
1295
|
+
directive @referencer6(someArg: Scalar) on MUTATION
|
|
1296
|
+
`);
|
|
1297
|
+
|
|
1298
|
+
const errorMessages = expectErrors(6, () => {
|
|
1299
|
+
removeInaccessibleElements(schema);
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1302
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
1303
|
+
Array [
|
|
1304
|
+
"Type \\"Scalar\\" is @inaccessible but is referenced by \\"@referencer6(someArg:)\\", which is in the API schema.",
|
|
1305
|
+
"Type \\"Scalar\\" is @inaccessible but is referenced by \\"Referencer1.somefield\\", which is in the API schema.",
|
|
1306
|
+
"Type \\"Scalar\\" is @inaccessible but is referenced by \\"Referencer2.somefield\\", which is in the API schema.",
|
|
1307
|
+
"Type \\"Scalar\\" is @inaccessible but is referenced by \\"Referencer3.someField(someArg:)\\", which is in the API schema.",
|
|
1308
|
+
"Type \\"Scalar\\" is @inaccessible but is referenced by \\"Referencer4.someField(someArg:)\\", which is in the API schema.",
|
|
1309
|
+
"Type \\"Scalar\\" is @inaccessible but is referenced by \\"Referencer5.someField\\", which is in the API schema.",
|
|
1310
|
+
]
|
|
1311
|
+
`);
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1314
|
+
it(`removes @inaccessible object fields`, () => {
|
|
1315
|
+
const schema = buildSchema(`
|
|
1316
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1317
|
+
|
|
1318
|
+
extend schema {
|
|
1319
|
+
mutation: Mutation
|
|
1320
|
+
subscription: Subscription
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
# Inaccessible object field on query type
|
|
1324
|
+
type Query {
|
|
1325
|
+
someField: String
|
|
1326
|
+
privateField: String @inaccessible
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
# Inaccessible object field on mutation type
|
|
1330
|
+
type Mutation {
|
|
1331
|
+
someField: String
|
|
1332
|
+
privateField: String @inaccessible
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
# Inaccessible object field on subscription type
|
|
1336
|
+
type Subscription {
|
|
1337
|
+
someField: String
|
|
1338
|
+
privateField: String @inaccessible
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
# Inaccessible (and non-inaccessible) object field
|
|
1342
|
+
type Object implements Referencer1 & Referencer2 {
|
|
1343
|
+
someField: String
|
|
1344
|
+
privateField: String @inaccessible
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
# Inaccessible object field referenced by inaccessible interface field
|
|
1348
|
+
interface Referencer1 {
|
|
1349
|
+
someField: String
|
|
1350
|
+
privateField: String @inaccessible
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
# Inaccessible object field referenced by non-inaccessible interface field
|
|
1354
|
+
# with inaccessible parent
|
|
1355
|
+
interface Referencer2 @inaccessible {
|
|
1356
|
+
privateField: String
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
# Inaccessible object field with an inaccessible parent and no
|
|
1360
|
+
# non-inaccessible siblings
|
|
1361
|
+
type Referencer3 @inaccessible {
|
|
1362
|
+
privateField: String @inaccessible
|
|
1363
|
+
otherPrivateField: Float @inaccessible
|
|
1364
|
+
}
|
|
1365
|
+
`);
|
|
1366
|
+
|
|
1367
|
+
removeInaccessibleElements(schema);
|
|
1368
|
+
schema.validate();
|
|
1369
|
+
expect(schema.elementByCoordinate("Query.someField")).toBeDefined();
|
|
1370
|
+
expect(schema.elementByCoordinate("Query.privateField")).toBeUndefined();
|
|
1371
|
+
expect(schema.elementByCoordinate("Mutation.someField")).toBeDefined();
|
|
1372
|
+
expect(schema.elementByCoordinate("Mutation.privateField")).toBeUndefined();
|
|
1373
|
+
expect(schema.elementByCoordinate("Subscription.someField")).toBeDefined();
|
|
1374
|
+
expect(
|
|
1375
|
+
schema.elementByCoordinate("Subscription.privateField")
|
|
1376
|
+
).toBeUndefined();
|
|
1377
|
+
const objectType = schema.elementByCoordinate("Object");
|
|
1378
|
+
expect(objectType instanceof ObjectType).toBeTruthy();
|
|
1379
|
+
expect(
|
|
1380
|
+
(objectType as ObjectType).implementsInterface("Referencer1")
|
|
1381
|
+
).toBeTruthy();
|
|
1382
|
+
expect(
|
|
1383
|
+
(objectType as ObjectType).implementsInterface("Referencer2")
|
|
1384
|
+
).toBeFalsy();
|
|
1385
|
+
expect(schema.elementByCoordinate("Object.someField")).toBeDefined();
|
|
1386
|
+
expect(schema.elementByCoordinate("Object.privateField")).toBeUndefined();
|
|
1387
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
1388
|
+
expect(
|
|
1389
|
+
schema.elementByCoordinate("Referencer1.privatefield")
|
|
1390
|
+
).toBeUndefined();
|
|
1391
|
+
expect(schema.elementByCoordinate("Referencer2")).toBeUndefined();
|
|
1392
|
+
expect(schema.elementByCoordinate("Referencer3")).toBeUndefined();
|
|
1393
|
+
});
|
|
1394
|
+
|
|
1395
|
+
it(`fails to remove @inaccessible object fields for breaking removals`, () => {
|
|
1396
|
+
const schema = buildSchema(`
|
|
1397
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1398
|
+
|
|
1399
|
+
extend schema {
|
|
1400
|
+
mutation: Mutation
|
|
1401
|
+
subscription: Subscription
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
# Inaccessible object field can't have a non-inaccessible parent query
|
|
1405
|
+
# type and no non-inaccessible siblings
|
|
1406
|
+
type Query {
|
|
1407
|
+
privateField: String @inaccessible
|
|
1408
|
+
otherPrivateField: Float @inaccessible
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
# Inaccessible object field can't have a non-inaccessible parent mutation
|
|
1412
|
+
# type and no non-inaccessible siblings
|
|
1413
|
+
type Mutation {
|
|
1414
|
+
privateField: String @inaccessible
|
|
1415
|
+
otherPrivateField: Float @inaccessible
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
# Inaccessible object field can't have a non-inaccessible parent
|
|
1419
|
+
# subscription type and no non-inaccessible siblings
|
|
1420
|
+
type Subscription {
|
|
1421
|
+
privateField: String @inaccessible
|
|
1422
|
+
otherPrivateField: Float @inaccessible
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
# Inaccessible object field
|
|
1426
|
+
type Object implements Referencer1 {
|
|
1427
|
+
someField: String
|
|
1428
|
+
privateField: String @inaccessible
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
# Inaccessible object field can't be referenced by interface field in the
|
|
1432
|
+
# API schema
|
|
1433
|
+
interface Referencer1 {
|
|
1434
|
+
privateField: String
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
# Inaccessible object field can't have a non-inaccessible parent object
|
|
1438
|
+
# type and no non-inaccessible siblings
|
|
1439
|
+
type Referencer2 {
|
|
1440
|
+
privateField: String @inaccessible
|
|
1441
|
+
otherPrivateField: Float @inaccessible
|
|
1442
|
+
}
|
|
1443
|
+
`);
|
|
1444
|
+
|
|
1445
|
+
const errorMessages = expectErrors(5, () => {
|
|
1446
|
+
removeInaccessibleElements(schema);
|
|
1447
|
+
});
|
|
1448
|
+
|
|
1449
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
1450
|
+
Array [
|
|
1451
|
+
"Field \\"Object.privateField\\" is @inaccessible but implements the interface field \\"Referencer1.privateField\\", which is in the API schema.",
|
|
1452
|
+
"Type \\"Mutation\\" is in the API schema but all of its fields are @inaccessible.",
|
|
1453
|
+
"Type \\"Query\\" is in the API schema but all of its fields are @inaccessible.",
|
|
1454
|
+
"Type \\"Referencer2\\" is in the API schema but all of its fields are @inaccessible.",
|
|
1455
|
+
"Type \\"Subscription\\" is in the API schema but all of its fields are @inaccessible.",
|
|
1456
|
+
]
|
|
1457
|
+
`);
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
it(`removes @inaccessible interface fields`, () => {
|
|
1461
|
+
const schema = buildSchema(`
|
|
1462
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1463
|
+
|
|
1464
|
+
type Query {
|
|
1465
|
+
someField: String
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
# Inaccessible (and non-inaccessible) interface field
|
|
1469
|
+
interface Interface implements Referencer1 & Referencer2 {
|
|
1470
|
+
someField: String
|
|
1471
|
+
privateField: String @inaccessible
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
# Inaccessible interface field referenced by inaccessible interface field
|
|
1475
|
+
interface Referencer1 {
|
|
1476
|
+
someField: String
|
|
1477
|
+
privateField: String @inaccessible
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
# Inaccessible interface field referenced by non-inaccessible interface
|
|
1481
|
+
# field with inaccessible parent
|
|
1482
|
+
interface Referencer2 @inaccessible {
|
|
1483
|
+
privateField: String
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
# Inaccessible interface field with an inaccessible parent and no
|
|
1487
|
+
# non-inaccessible siblings
|
|
1488
|
+
interface Referencer3 @inaccessible {
|
|
1489
|
+
privateField: String @inaccessible
|
|
1490
|
+
otherPrivateField: Float @inaccessible
|
|
1491
|
+
}
|
|
1492
|
+
`);
|
|
1493
|
+
|
|
1494
|
+
removeInaccessibleElements(schema);
|
|
1495
|
+
schema.validate();
|
|
1496
|
+
const interfaceType = schema.elementByCoordinate("Interface");
|
|
1497
|
+
expect(interfaceType instanceof InterfaceType).toBeTruthy();
|
|
1498
|
+
expect(
|
|
1499
|
+
(interfaceType as InterfaceType).implementsInterface("Referencer1")
|
|
1500
|
+
).toBeTruthy();
|
|
1501
|
+
expect(
|
|
1502
|
+
(interfaceType as InterfaceType).implementsInterface("Referencer2")
|
|
1503
|
+
).toBeFalsy();
|
|
1504
|
+
expect(schema.elementByCoordinate("Interface.someField")).toBeDefined();
|
|
1505
|
+
expect(
|
|
1506
|
+
schema.elementByCoordinate("Interface.privateField")
|
|
1507
|
+
).toBeUndefined();
|
|
1508
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
1509
|
+
expect(
|
|
1510
|
+
schema.elementByCoordinate("Referencer1.privatefield")
|
|
1511
|
+
).toBeUndefined();
|
|
1512
|
+
expect(schema.elementByCoordinate("Referencer2")).toBeUndefined();
|
|
1513
|
+
expect(schema.elementByCoordinate("Referencer3")).toBeUndefined();
|
|
1514
|
+
});
|
|
1515
|
+
|
|
1516
|
+
it(`fails to remove @inaccessible interface fields for breaking removals`, () => {
|
|
1517
|
+
const schema = buildSchema(`
|
|
1518
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1519
|
+
|
|
1520
|
+
type Query {
|
|
1521
|
+
someField: String
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
# Inaccessible interface field
|
|
1525
|
+
interface Interface implements Referencer1 {
|
|
1526
|
+
someField: String
|
|
1527
|
+
privateField: String @inaccessible
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
# Inaccessible interface field can't be referenced by interface field in
|
|
1531
|
+
# the API schema
|
|
1532
|
+
interface Referencer1 {
|
|
1533
|
+
privateField: String
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
# Inaccessible interface field can't have a non-inaccessible parent object
|
|
1537
|
+
# type and no non-inaccessible siblings
|
|
1538
|
+
interface Referencer2 {
|
|
1539
|
+
privateField: String @inaccessible
|
|
1540
|
+
otherPrivateField: Float @inaccessible
|
|
1541
|
+
}
|
|
1542
|
+
`);
|
|
1543
|
+
|
|
1544
|
+
const errorMessages = expectErrors(2, () => {
|
|
1545
|
+
removeInaccessibleElements(schema);
|
|
1546
|
+
});
|
|
1547
|
+
|
|
1548
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
1549
|
+
Array [
|
|
1550
|
+
"Field \\"Interface.privateField\\" is @inaccessible but implements the interface field \\"Referencer1.privateField\\", which is in the API schema.",
|
|
1551
|
+
"Type \\"Referencer2\\" is in the API schema but all of its fields are @inaccessible.",
|
|
1552
|
+
]
|
|
1553
|
+
`);
|
|
1554
|
+
});
|
|
1555
|
+
|
|
1556
|
+
it(`removes @inaccessible object field arguments`, () => {
|
|
1557
|
+
const schema = buildSchema(`
|
|
1558
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1559
|
+
|
|
1560
|
+
# Inaccessible object field argument in query type
|
|
1561
|
+
type Query {
|
|
1562
|
+
someField(privateArg: String @inaccessible): String
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
# Inaccessible object field argument in mutation type
|
|
1566
|
+
type Mutation {
|
|
1567
|
+
someField(privateArg: String @inaccessible): String
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
# Inaccessible object field argument in subscription type
|
|
1571
|
+
type Subscription {
|
|
1572
|
+
someField(privateArg: String @inaccessible): String
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
# Inaccessible (and non-inaccessible) object field argument
|
|
1576
|
+
type Object implements Referencer1 & Referencer2 & Referencer3 {
|
|
1577
|
+
someField(
|
|
1578
|
+
someArg: String,
|
|
1579
|
+
privateArg: String @inaccessible
|
|
1580
|
+
): String
|
|
1581
|
+
someOtherField: Float
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
# Inaccessible object field argument referenced by inaccessible interface
|
|
1585
|
+
# field argument
|
|
1586
|
+
interface Referencer1 {
|
|
1587
|
+
someField(
|
|
1588
|
+
someArg: String,
|
|
1589
|
+
privateArg: String @inaccessible
|
|
1590
|
+
): String
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
# Inaccessible object field argument referenced by non-inaccessible
|
|
1594
|
+
# interface field argument with inaccessible parent
|
|
1595
|
+
interface Referencer2 {
|
|
1596
|
+
someField(
|
|
1597
|
+
someArg: String,
|
|
1598
|
+
privateArg: String
|
|
1599
|
+
): String @inaccessible
|
|
1600
|
+
someOtherField: Float
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
# Inaccessible object field argument referenced by non-inaccessible
|
|
1604
|
+
# interface field argument with inaccessible grandparent
|
|
1605
|
+
interface Referencer3 @inaccessible {
|
|
1606
|
+
someField(
|
|
1607
|
+
someArg: String,
|
|
1608
|
+
privateArg: String
|
|
1609
|
+
): String
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
# Inaccessible non-nullable object field argument with default
|
|
1613
|
+
type ObjectDefault {
|
|
1614
|
+
someField(privateArg: String! = "default" @inaccessible): String
|
|
1615
|
+
}
|
|
1616
|
+
`);
|
|
1617
|
+
|
|
1618
|
+
removeInaccessibleElements(schema);
|
|
1619
|
+
schema.validate();
|
|
1620
|
+
expect(schema.elementByCoordinate("Query.someField")).toBeDefined();
|
|
1621
|
+
expect(
|
|
1622
|
+
schema.elementByCoordinate("Query.someField(privateArg:)")
|
|
1623
|
+
).toBeUndefined();
|
|
1624
|
+
expect(schema.elementByCoordinate("Mutation.someField")).toBeDefined();
|
|
1625
|
+
expect(
|
|
1626
|
+
schema.elementByCoordinate("Mutation.someField(privateArg:)")
|
|
1627
|
+
).toBeUndefined();
|
|
1628
|
+
expect(schema.elementByCoordinate("Subscription.someField")).toBeDefined();
|
|
1629
|
+
expect(
|
|
1630
|
+
schema.elementByCoordinate("Subscription.someField(privateArg:)")
|
|
1631
|
+
).toBeUndefined();
|
|
1632
|
+
const objectType = schema.elementByCoordinate("Object");
|
|
1633
|
+
expect(objectType instanceof ObjectType).toBeTruthy();
|
|
1634
|
+
expect(
|
|
1635
|
+
(objectType as ObjectType).implementsInterface("Referencer1")
|
|
1636
|
+
).toBeTruthy();
|
|
1637
|
+
expect(
|
|
1638
|
+
(objectType as ObjectType).implementsInterface("Referencer2")
|
|
1639
|
+
).toBeTruthy();
|
|
1640
|
+
expect(
|
|
1641
|
+
(objectType as ObjectType).implementsInterface("Referencer3")
|
|
1642
|
+
).toBeFalsy();
|
|
1643
|
+
expect(
|
|
1644
|
+
schema.elementByCoordinate("Object.someField(someArg:)")
|
|
1645
|
+
).toBeDefined();
|
|
1646
|
+
expect(
|
|
1647
|
+
schema.elementByCoordinate("Object.someField(privateArg:)")
|
|
1648
|
+
).toBeUndefined();
|
|
1649
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
1650
|
+
expect(
|
|
1651
|
+
schema.elementByCoordinate("Referencer1.someField(privateArg:)")
|
|
1652
|
+
).toBeUndefined();
|
|
1653
|
+
expect(schema.elementByCoordinate("Referencer2")).toBeDefined();
|
|
1654
|
+
expect(schema.elementByCoordinate("Referencer2.someField")).toBeUndefined();
|
|
1655
|
+
expect(schema.elementByCoordinate("Referencer3")).toBeUndefined();
|
|
1656
|
+
expect(schema.elementByCoordinate("ObjectDefault.someField")).toBeDefined();
|
|
1657
|
+
expect(
|
|
1658
|
+
schema.elementByCoordinate("ObjectDefault.someField(privateArg:)")
|
|
1659
|
+
).toBeUndefined();
|
|
1660
|
+
});
|
|
1661
|
+
|
|
1662
|
+
it(`fails to remove @inaccessible object field arguments for breaking removals`, () => {
|
|
1663
|
+
const schema = buildSchema(`
|
|
1664
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1665
|
+
|
|
1666
|
+
type Query {
|
|
1667
|
+
someField(someArg: String): String
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
# Inaccessible object field argument
|
|
1671
|
+
type Object implements Referencer1 {
|
|
1672
|
+
someField(privateArg: String @inaccessible): String
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
# Inaccessible object field argument can't be referenced by interface
|
|
1676
|
+
# field argument in the API schema
|
|
1677
|
+
interface Referencer1 {
|
|
1678
|
+
someField(privateArg: String): String
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
# Inaccessible object field argument can't be a required argument
|
|
1682
|
+
type ObjectRequired {
|
|
1683
|
+
someField(privateArg: String! @inaccessible): String
|
|
1684
|
+
}
|
|
1685
|
+
`);
|
|
1686
|
+
|
|
1687
|
+
const errorMessages = expectErrors(2, () => {
|
|
1688
|
+
removeInaccessibleElements(schema);
|
|
1689
|
+
});
|
|
1690
|
+
|
|
1691
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
1692
|
+
Array [
|
|
1693
|
+
"Argument \\"Object.someField(privateArg:)\\" is @inaccessible but implements the interface argument \\"Referencer1.someField(privateArg:)\\", which is in the API schema.",
|
|
1694
|
+
"Argument \\"ObjectRequired.someField(privateArg:)\\" is @inaccessible but is a required argument of its field.",
|
|
1695
|
+
]
|
|
1696
|
+
`);
|
|
1697
|
+
});
|
|
1698
|
+
|
|
1699
|
+
it(`removes @inaccessible interface field arguments`, () => {
|
|
1700
|
+
const schema = buildSchema(`
|
|
1701
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1702
|
+
|
|
1703
|
+
type Query {
|
|
1704
|
+
someField: String
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
# Inaccessible (and non-inaccessible) interface field argument
|
|
1708
|
+
interface Interface implements Referencer1 & Referencer2 & Referencer3 {
|
|
1709
|
+
someField(
|
|
1710
|
+
someArg: String,
|
|
1711
|
+
privateArg: String @inaccessible
|
|
1712
|
+
): String
|
|
1713
|
+
someOtherField: Float
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
# Inaccessible interface field argument referenced by inaccessible
|
|
1717
|
+
# interface field argument
|
|
1718
|
+
interface Referencer1 {
|
|
1719
|
+
someField(
|
|
1720
|
+
someArg: String,
|
|
1721
|
+
privateArg: String @inaccessible
|
|
1722
|
+
): String
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
# Inaccessible interface field argument referenced by non-inaccessible
|
|
1726
|
+
# interface field argument with inaccessible parent
|
|
1727
|
+
interface Referencer2 {
|
|
1728
|
+
someField(
|
|
1729
|
+
someArg: String,
|
|
1730
|
+
privateArg: String
|
|
1731
|
+
): String @inaccessible
|
|
1732
|
+
someOtherField: Float
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
# Inaccessible interface field argument referenced by non-inaccessible
|
|
1736
|
+
# interface field argument with inaccessible grandparent
|
|
1737
|
+
interface Referencer3 @inaccessible {
|
|
1738
|
+
someField(
|
|
1739
|
+
someArg: String,
|
|
1740
|
+
privateArg: String
|
|
1741
|
+
): String
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
# Inaccessible non-nullable interface field argument with default
|
|
1745
|
+
interface InterfaceDefault {
|
|
1746
|
+
someField(privateArg: String! = "default" @inaccessible): String
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
# Inaccessible interface field argument referenced by non-inaccessible
|
|
1750
|
+
# non-required object field argument
|
|
1751
|
+
type Referencer4 implements InterfaceDefault {
|
|
1752
|
+
someField(privateArg: String! = "default"): String
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
# Inaccessible interface field argument referenced by non-inaccessible
|
|
1756
|
+
# required object field argument with inaccessible grandparent
|
|
1757
|
+
type Referencer5 implements InterfaceDefault @inaccessible {
|
|
1758
|
+
someField(privateArg: String!): String
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
# Inaccessible interface field argument referenced by non-inaccessible
|
|
1762
|
+
# non-required interface field argument
|
|
1763
|
+
interface Referencer6 implements InterfaceDefault {
|
|
1764
|
+
someField(privateArg: String! = "default"): String
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
# Inaccessible interface field argument referenced by non-inaccessible
|
|
1768
|
+
# required interface field argument with inaccessible grandparent
|
|
1769
|
+
interface Referencer7 implements InterfaceDefault @inaccessible {
|
|
1770
|
+
someField(privateArg: String!): String
|
|
1771
|
+
}
|
|
1772
|
+
`);
|
|
1773
|
+
|
|
1774
|
+
removeInaccessibleElements(schema);
|
|
1775
|
+
schema.validate();
|
|
1776
|
+
const interfaceType = schema.elementByCoordinate("Interface");
|
|
1777
|
+
expect(interfaceType instanceof InterfaceType).toBeTruthy();
|
|
1778
|
+
expect(
|
|
1779
|
+
(interfaceType as InterfaceType).implementsInterface("Referencer1")
|
|
1780
|
+
).toBeTruthy();
|
|
1781
|
+
expect(
|
|
1782
|
+
(interfaceType as InterfaceType).implementsInterface("Referencer2")
|
|
1783
|
+
).toBeTruthy();
|
|
1784
|
+
expect(
|
|
1785
|
+
(interfaceType as InterfaceType).implementsInterface("Referencer3")
|
|
1786
|
+
).toBeFalsy();
|
|
1787
|
+
expect(
|
|
1788
|
+
schema.elementByCoordinate("Interface.someField(someArg:)")
|
|
1789
|
+
).toBeDefined();
|
|
1790
|
+
expect(
|
|
1791
|
+
schema.elementByCoordinate("Interface.someField(privateArg:)")
|
|
1792
|
+
).toBeUndefined();
|
|
1793
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
1794
|
+
expect(
|
|
1795
|
+
schema.elementByCoordinate("Referencer1.someField(privateArg:)")
|
|
1796
|
+
).toBeUndefined();
|
|
1797
|
+
expect(schema.elementByCoordinate("Referencer2")).toBeDefined();
|
|
1798
|
+
expect(schema.elementByCoordinate("Referencer2.someField")).toBeUndefined();
|
|
1799
|
+
expect(schema.elementByCoordinate("Referencer3")).toBeUndefined();
|
|
1800
|
+
expect(schema.elementByCoordinate("Interface.someField")).toBeDefined();
|
|
1801
|
+
expect(
|
|
1802
|
+
schema.elementByCoordinate("Interface.someField(privateArg:)")
|
|
1803
|
+
).toBeUndefined();
|
|
1804
|
+
const objectArg = schema.elementByCoordinate(
|
|
1805
|
+
"Referencer4.someField(privateArg:)"
|
|
1806
|
+
);
|
|
1807
|
+
expect(objectArg instanceof ArgumentDefinition).toBeTruthy();
|
|
1808
|
+
expect(
|
|
1809
|
+
(
|
|
1810
|
+
objectArg as ArgumentDefinition<FieldDefinition<ObjectType>>
|
|
1811
|
+
).isRequired()
|
|
1812
|
+
).toBeFalsy();
|
|
1813
|
+
expect(schema.elementByCoordinate("Referencer5")).toBeUndefined();
|
|
1814
|
+
const interfaceArg = schema.elementByCoordinate(
|
|
1815
|
+
"Referencer6.someField(privateArg:)"
|
|
1816
|
+
);
|
|
1817
|
+
expect(interfaceArg instanceof ArgumentDefinition).toBeTruthy();
|
|
1818
|
+
expect(
|
|
1819
|
+
(
|
|
1820
|
+
interfaceArg as ArgumentDefinition<FieldDefinition<InterfaceType>>
|
|
1821
|
+
).isRequired()
|
|
1822
|
+
).toBeFalsy();
|
|
1823
|
+
expect(schema.elementByCoordinate("Referencer7")).toBeUndefined();
|
|
1824
|
+
});
|
|
1825
|
+
|
|
1826
|
+
it(`fails to remove @inaccessible interface field arguments for breaking removals`, () => {
|
|
1827
|
+
const schema = buildSchema(`
|
|
1828
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1829
|
+
|
|
1830
|
+
type Query {
|
|
1831
|
+
someField(someArg: String): String
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
# Inaccessible interface field argument
|
|
1835
|
+
interface Interface implements Referencer1 {
|
|
1836
|
+
someField(privateArg: String! = "default" @inaccessible): String
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
# Inaccessible interface field argument can't be referenced by interface
|
|
1840
|
+
# field argument in the API schema
|
|
1841
|
+
interface Referencer1 {
|
|
1842
|
+
someField(privateArg: String! = "default"): String
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
# Inaccessible object field argument can't be a required argument
|
|
1846
|
+
type InterfaceRequired {
|
|
1847
|
+
someField(privateArg: String! @inaccessible): String
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
# Inaccessible object field argument can't be implemented by a required
|
|
1851
|
+
# object field argument in the API schema
|
|
1852
|
+
type Referencer2 implements Interface & Referencer1 {
|
|
1853
|
+
someField(privateArg: String!): String
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
# Inaccessible object field argument can't be implemented by a required
|
|
1857
|
+
# interface field argument in the API schema
|
|
1858
|
+
interface Referencer3 implements Interface & Referencer1 {
|
|
1859
|
+
someField(privateArg: String!): String
|
|
1860
|
+
}
|
|
1861
|
+
`);
|
|
1862
|
+
|
|
1863
|
+
const errorMessages = expectErrors(4, () => {
|
|
1864
|
+
removeInaccessibleElements(schema);
|
|
1865
|
+
});
|
|
1866
|
+
|
|
1867
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
1868
|
+
Array [
|
|
1869
|
+
"Argument \\"Interface.someField(privateArg:)\\" is @inaccessible but implements the interface argument \\"Referencer1.someField(privateArg:)\\", which is in the API schema.",
|
|
1870
|
+
"Argument \\"Interface.someField(privateArg:)\\" is @inaccessible but is implemented by the required argument \\"Referencer2.someField(privateArg:)\\", which is in the API schema.",
|
|
1871
|
+
"Argument \\"Interface.someField(privateArg:)\\" is @inaccessible but is implemented by the required argument \\"Referencer3.someField(privateArg:)\\", which is in the API schema.",
|
|
1872
|
+
"Argument \\"InterfaceRequired.someField(privateArg:)\\" is @inaccessible but is a required argument of its field.",
|
|
1873
|
+
]
|
|
1874
|
+
`);
|
|
1875
|
+
});
|
|
1876
|
+
|
|
1877
|
+
it(`removes @inaccessible input object fields`, () => {
|
|
1878
|
+
const schema = buildSchema(`
|
|
1879
|
+
${INACCESSIBLE_V02_HEADER}
|
|
1880
|
+
|
|
1881
|
+
type Query {
|
|
1882
|
+
someField: String
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
# Inaccessible (and non-inaccessible) input object field
|
|
1886
|
+
input InputObject {
|
|
1887
|
+
someField: String
|
|
1888
|
+
privateField: String @inaccessible
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
# Inaccessible input object field referenced by default value of
|
|
1892
|
+
# inaccessible object field argument
|
|
1893
|
+
type Referencer1 implements Referencer4 {
|
|
1894
|
+
someField(
|
|
1895
|
+
privateArg: InputObject = { privateField: "" } @inaccessible
|
|
1896
|
+
): String
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
# Inaccessible input object field referenced by default value of
|
|
1900
|
+
# non-inaccessible object field argument with inaccessible parent
|
|
1901
|
+
type Referencer2 implements Referencer5 {
|
|
1902
|
+
someField: String
|
|
1903
|
+
privateField(
|
|
1904
|
+
privateArg: InputObject! = { privateField: "" }
|
|
1905
|
+
): String @inaccessible
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
# Inaccessible input object field referenced by default value of
|
|
1909
|
+
# non-inaccessible object field argument with inaccessible grandparent
|
|
1910
|
+
type Referencer3 implements Referencer6 @inaccessible {
|
|
1911
|
+
privateField(privateArg: InputObject! = { privateField: "" }): String
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
# Inaccessible input object field referenced by default value of
|
|
1915
|
+
# inaccessible interface field argument
|
|
1916
|
+
interface Referencer4 {
|
|
1917
|
+
someField(
|
|
1918
|
+
privateArg: InputObject = { privateField: "" } @inaccessible
|
|
1919
|
+
): String
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
# Inaccessible input object field referenced by default value of
|
|
1923
|
+
# non-inaccessible interface field argument with inaccessible parent
|
|
1924
|
+
interface Referencer5 {
|
|
1925
|
+
someField: String
|
|
1926
|
+
privateField(
|
|
1927
|
+
privateArg: InputObject! = { privateField: "" }
|
|
1928
|
+
): String @inaccessible
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
# Inaccessible input object field referenced by default value of
|
|
1932
|
+
# non-inaccessible interface field argument with inaccessible grandparent
|
|
1933
|
+
interface Referencer6 @inaccessible {
|
|
1934
|
+
privateField(privateArg: InputObject! = { privateField: "" }): String
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
# Inaccessible input object field referenced by default value of
|
|
1938
|
+
# inaccessible input object field
|
|
1939
|
+
input Referencer7 {
|
|
1940
|
+
someField: String
|
|
1941
|
+
privateField: InputObject = { privateField: "" } @inaccessible
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
# Inaccessible input object field referenced by default value of
|
|
1945
|
+
# non-inaccessible input object field with inaccessible parent
|
|
1946
|
+
input Referencer8 @inaccessible {
|
|
1947
|
+
privateField: InputObject! = { privateField: "" }
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
# Inaccessible input object field referenced by default value of
|
|
1951
|
+
# inaccessible directive argument
|
|
1952
|
+
directive @referencer9(
|
|
1953
|
+
privateArg: InputObject = { privateField: "" } @inaccessible
|
|
1954
|
+
) on SUBSCRIPTION
|
|
1955
|
+
|
|
1956
|
+
# Inaccessible input object field not referenced (but type is referenced)
|
|
1957
|
+
# by default value of object field argument in the API schema
|
|
1958
|
+
type Referencer10 {
|
|
1959
|
+
someField(privateArg: InputObject = { someField: "" }): String
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
# Inaccessible input object field with an inaccessible parent and no
|
|
1963
|
+
# non-inaccessible siblings
|
|
1964
|
+
input Referencer11 @inaccessible {
|
|
1965
|
+
privateField: String @inaccessible
|
|
1966
|
+
otherPrivateField: Float @inaccessible
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
# Inaccessible non-nullable input object field with default
|
|
1970
|
+
input InputObjectDefault {
|
|
1971
|
+
someField: String
|
|
1972
|
+
privateField: String! = "default" @inaccessible
|
|
1973
|
+
}
|
|
1974
|
+
`);
|
|
1975
|
+
|
|
1976
|
+
removeInaccessibleElements(schema);
|
|
1977
|
+
schema.validate();
|
|
1978
|
+
expect(schema.elementByCoordinate("InputObject.someField")).toBeDefined();
|
|
1979
|
+
expect(
|
|
1980
|
+
schema.elementByCoordinate("InputObject.privateField")
|
|
1981
|
+
).toBeUndefined();
|
|
1982
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
1983
|
+
expect(
|
|
1984
|
+
schema.elementByCoordinate("Referencer1.someField(privateArg:)")
|
|
1985
|
+
).toBeUndefined();
|
|
1986
|
+
expect(schema.elementByCoordinate("Referencer2.someField")).toBeDefined();
|
|
1987
|
+
expect(
|
|
1988
|
+
schema.elementByCoordinate("Referencer2.privateField")
|
|
1989
|
+
).toBeUndefined();
|
|
1990
|
+
expect(schema.elementByCoordinate("Referencer3")).toBeUndefined();
|
|
1991
|
+
expect(schema.elementByCoordinate("Referencer4.someField")).toBeDefined();
|
|
1992
|
+
expect(
|
|
1993
|
+
schema.elementByCoordinate("Referencer4.someField(privateArg:)")
|
|
1994
|
+
).toBeUndefined();
|
|
1995
|
+
expect(schema.elementByCoordinate("Referencer5.someField")).toBeDefined();
|
|
1996
|
+
expect(
|
|
1997
|
+
schema.elementByCoordinate("Referencer5.privateField")
|
|
1998
|
+
).toBeUndefined();
|
|
1999
|
+
expect(schema.elementByCoordinate("Referencer6")).toBeUndefined();
|
|
2000
|
+
expect(schema.elementByCoordinate("Referencer7.someField")).toBeDefined();
|
|
2001
|
+
expect(
|
|
2002
|
+
schema.elementByCoordinate("Referencer7.privatefield")
|
|
2003
|
+
).toBeUndefined();
|
|
2004
|
+
expect(schema.elementByCoordinate("Referencer8")).toBeUndefined();
|
|
2005
|
+
expect(schema.elementByCoordinate("@referencer9")).toBeDefined();
|
|
2006
|
+
expect(
|
|
2007
|
+
schema.elementByCoordinate("@referencer9(privateArg:)")
|
|
2008
|
+
).toBeUndefined();
|
|
2009
|
+
expect(
|
|
2010
|
+
schema.elementByCoordinate("Referencer10.someField(privateArg:)")
|
|
2011
|
+
).toBeDefined();
|
|
2012
|
+
expect(schema.elementByCoordinate("Referencer11")).toBeUndefined();
|
|
2013
|
+
expect(
|
|
2014
|
+
schema.elementByCoordinate("InputObjectDefault.someField")
|
|
2015
|
+
).toBeDefined();
|
|
2016
|
+
expect(
|
|
2017
|
+
schema.elementByCoordinate("InputObjectDefault.privatefield")
|
|
2018
|
+
).toBeUndefined();
|
|
2019
|
+
});
|
|
2020
|
+
|
|
2021
|
+
it(`fails to remove @inaccessible input object fields for breaking removals`, () => {
|
|
2022
|
+
const schema = buildSchema(`
|
|
2023
|
+
${INACCESSIBLE_V02_HEADER}
|
|
2024
|
+
|
|
2025
|
+
type Query {
|
|
2026
|
+
someField: String
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
# Inaccessible input object field
|
|
2030
|
+
input InputObject {
|
|
2031
|
+
someField: String
|
|
2032
|
+
privateField: String @inaccessible
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
# Inaccessible input object field can't be referenced by default value of
|
|
2036
|
+
# object field argument in the API schema
|
|
2037
|
+
type Referencer1 implements Referencer2 {
|
|
2038
|
+
someField(someArg: InputObject = { privateField: "" }): String
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
# Inaccessible input object field can't be referenced by default value of
|
|
2042
|
+
# interface field argument in the API schema
|
|
2043
|
+
interface Referencer2 {
|
|
2044
|
+
someField(someArg: InputObject = { privateField: "" }): String
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
# Inaccessible input object field can't be referenced by default value of
|
|
2048
|
+
# input object field in the API schema
|
|
2049
|
+
input Referencer3 {
|
|
2050
|
+
someField: InputObject = { privateField: "" }
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
# Inaccessible input object field can't be referenced by default value of
|
|
2054
|
+
# directive argument in the API schema
|
|
2055
|
+
directive @referencer4(
|
|
2056
|
+
someArg: InputObject = { privateField: "" }
|
|
2057
|
+
) on FIELD
|
|
2058
|
+
|
|
2059
|
+
# Inaccessible input object field can't have a non-inaccessible parent
|
|
2060
|
+
# and no non-inaccessible siblings
|
|
2061
|
+
input Referencer5 {
|
|
2062
|
+
privateField: String @inaccessible
|
|
2063
|
+
otherPrivateField: Float @inaccessible
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
# Inaccessible input object field can't be a required field
|
|
2067
|
+
input InputObjectRequired {
|
|
2068
|
+
someField: String
|
|
2069
|
+
privateField: String! @inaccessible
|
|
2070
|
+
}
|
|
2071
|
+
`);
|
|
2072
|
+
|
|
2073
|
+
const errorMessages = expectErrors(6, () => {
|
|
2074
|
+
removeInaccessibleElements(schema);
|
|
2075
|
+
});
|
|
2076
|
+
|
|
2077
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
2078
|
+
Array [
|
|
2079
|
+
"Input field \\"InputObject.privateField\\" is @inaccessible but is used in the default value of \\"@referencer4(someArg:)\\", which is in the API schema.",
|
|
2080
|
+
"Input field \\"InputObject.privateField\\" is @inaccessible but is used in the default value of \\"Referencer1.someField(someArg:)\\", which is in the API schema.",
|
|
2081
|
+
"Input field \\"InputObject.privateField\\" is @inaccessible but is used in the default value of \\"Referencer2.someField(someArg:)\\", which is in the API schema.",
|
|
2082
|
+
"Input field \\"InputObject.privateField\\" is @inaccessible but is used in the default value of \\"Referencer3.someField\\", which is in the API schema.",
|
|
2083
|
+
"Input field \\"InputObjectRequired.privateField\\" is @inaccessible but is a required input field of its type.",
|
|
2084
|
+
"Type \\"Referencer5\\" is in the API schema but all of its input fields are @inaccessible.",
|
|
2085
|
+
]
|
|
2086
|
+
`);
|
|
2087
|
+
});
|
|
2088
|
+
|
|
2089
|
+
it(`removes @inaccessible enum values`, () => {
|
|
2090
|
+
const schema = buildSchema(`
|
|
2091
|
+
${INACCESSIBLE_V02_HEADER}
|
|
2092
|
+
|
|
2093
|
+
type Query {
|
|
2094
|
+
someField: String
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
# Inaccessible (and non-inaccessible) enum value
|
|
2098
|
+
enum Enum {
|
|
2099
|
+
SOME_VALUE
|
|
2100
|
+
PRIVATE_VALUE @inaccessible
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
# Inaccessible enum value referenced by default value of inaccessible
|
|
2104
|
+
# object field argument
|
|
2105
|
+
type Referencer1 implements Referencer4 {
|
|
2106
|
+
someField(
|
|
2107
|
+
privateArg: Enum = PRIVATE_VALUE @inaccessible
|
|
2108
|
+
): String
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
# Inaccessible enum value referenced by default value of non-inaccessible
|
|
2112
|
+
# object field argument with inaccessible parent
|
|
2113
|
+
type Referencer2 implements Referencer5 {
|
|
2114
|
+
someField: String
|
|
2115
|
+
privateField(
|
|
2116
|
+
privateArg: Enum! = PRIVATE_VALUE
|
|
2117
|
+
): String @inaccessible
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
# Inaccessible enum value referenced by default value of non-inaccessible
|
|
2121
|
+
# object field argument with inaccessible grandparent
|
|
2122
|
+
type Referencer3 implements Referencer6 @inaccessible {
|
|
2123
|
+
privateField(privateArg: Enum! = PRIVATE_VALUE): String
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
# Inaccessible enum value referenced by default value of inaccessible
|
|
2127
|
+
# interface field argument
|
|
2128
|
+
interface Referencer4 {
|
|
2129
|
+
someField(
|
|
2130
|
+
privateArg: Enum = PRIVATE_VALUE @inaccessible
|
|
2131
|
+
): String
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
# Inaccessible enum value referenced by default value of non-inaccessible
|
|
2135
|
+
# interface field argument with inaccessible parent
|
|
2136
|
+
interface Referencer5 {
|
|
2137
|
+
someField: String
|
|
2138
|
+
privateField(
|
|
2139
|
+
privateArg: Enum! = PRIVATE_VALUE
|
|
2140
|
+
): String @inaccessible
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
# Inaccessible enum value referenced by default value of non-inaccessible
|
|
2144
|
+
# interface field argument with inaccessible grandparent
|
|
2145
|
+
interface Referencer6 @inaccessible {
|
|
2146
|
+
privateField(privateArg: Enum! = PRIVATE_VALUE): String
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
# Inaccessible enum value referenced by default value of inaccessible
|
|
2150
|
+
# input object field
|
|
2151
|
+
input Referencer7 {
|
|
2152
|
+
someField: String
|
|
2153
|
+
privateField: Enum = PRIVATE_VALUE @inaccessible
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
# Inaccessible enum value referenced by default value of non-inaccessible
|
|
2157
|
+
# input object field with inaccessible parent
|
|
2158
|
+
input Referencer8 @inaccessible {
|
|
2159
|
+
privateField: Enum! = PRIVATE_VALUE
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
# Inaccessible enum value referenced by default value of inaccessible
|
|
2163
|
+
# directive argument
|
|
2164
|
+
directive @referencer9(
|
|
2165
|
+
privateArg: Enum = PRIVATE_VALUE @inaccessible
|
|
2166
|
+
) on FRAGMENT_SPREAD
|
|
2167
|
+
|
|
2168
|
+
# Inaccessible enum value not referenced (but type is referenced) by
|
|
2169
|
+
# default value of object field argument in the API schema
|
|
2170
|
+
type Referencer10 {
|
|
2171
|
+
someField(privateArg: Enum = SOME_VALUE): String
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
# Inaccessible enum value with an inaccessible parent and no
|
|
2175
|
+
# non-inaccessible siblings
|
|
2176
|
+
enum Referencer11 @inaccessible {
|
|
2177
|
+
PRIVATE_VALUE @inaccessible
|
|
2178
|
+
OTHER_PRIVATE_VALUE @inaccessible
|
|
2179
|
+
}
|
|
2180
|
+
`);
|
|
2181
|
+
|
|
2182
|
+
removeInaccessibleElements(schema);
|
|
2183
|
+
schema.validate();
|
|
2184
|
+
expect(schema.elementByCoordinate("Enum.SOME_VALUE")).toBeDefined();
|
|
2185
|
+
expect(schema.elementByCoordinate("Enum.PRIVATE_VALUE")).toBeUndefined();
|
|
2186
|
+
expect(schema.elementByCoordinate("Referencer1.someField")).toBeDefined();
|
|
2187
|
+
expect(
|
|
2188
|
+
schema.elementByCoordinate("Referencer1.someField(privateArg:)")
|
|
2189
|
+
).toBeUndefined();
|
|
2190
|
+
expect(schema.elementByCoordinate("Referencer2.someField")).toBeDefined();
|
|
2191
|
+
expect(
|
|
2192
|
+
schema.elementByCoordinate("Referencer2.privateField")
|
|
2193
|
+
).toBeUndefined();
|
|
2194
|
+
expect(schema.elementByCoordinate("Referencer3")).toBeUndefined();
|
|
2195
|
+
expect(schema.elementByCoordinate("Referencer4.someField")).toBeDefined();
|
|
2196
|
+
expect(
|
|
2197
|
+
schema.elementByCoordinate("Referencer4.someField(privateArg:)")
|
|
2198
|
+
).toBeUndefined();
|
|
2199
|
+
expect(schema.elementByCoordinate("Referencer5.someField")).toBeDefined();
|
|
2200
|
+
expect(
|
|
2201
|
+
schema.elementByCoordinate("Referencer5.privateField")
|
|
2202
|
+
).toBeUndefined();
|
|
2203
|
+
expect(schema.elementByCoordinate("Referencer6")).toBeUndefined();
|
|
2204
|
+
expect(schema.elementByCoordinate("Referencer7.someField")).toBeDefined();
|
|
2205
|
+
expect(
|
|
2206
|
+
schema.elementByCoordinate("Referencer7.privatefield")
|
|
2207
|
+
).toBeUndefined();
|
|
2208
|
+
expect(schema.elementByCoordinate("Referencer8")).toBeUndefined();
|
|
2209
|
+
expect(schema.elementByCoordinate("@referencer9")).toBeDefined();
|
|
2210
|
+
expect(
|
|
2211
|
+
schema.elementByCoordinate("@referencer9(privateArg:)")
|
|
2212
|
+
).toBeUndefined();
|
|
2213
|
+
expect(
|
|
2214
|
+
schema.elementByCoordinate("Referencer10.someField(privateArg:)")
|
|
2215
|
+
).toBeDefined();
|
|
2216
|
+
expect(schema.elementByCoordinate("Referencer11")).toBeUndefined();
|
|
2217
|
+
});
|
|
2218
|
+
|
|
2219
|
+
it(`fails to remove @inaccessible enum values for breaking removals`, () => {
|
|
2220
|
+
const schema = buildSchema(`
|
|
2221
|
+
${INACCESSIBLE_V02_HEADER}
|
|
2222
|
+
|
|
2223
|
+
type Query {
|
|
2224
|
+
someField: String
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
# Inaccessible enum value
|
|
2228
|
+
enum Enum {
|
|
2229
|
+
SOME_VALUE
|
|
2230
|
+
PRIVATE_VALUE @inaccessible
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
# Inaccessible enum value can't be referenced by default value of object
|
|
2234
|
+
# field argument in the API schema
|
|
2235
|
+
type Referencer1 implements Referencer2 {
|
|
2236
|
+
someField(someArg: Enum = PRIVATE_VALUE): String
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
# Inaccessible enum value can't be referenced by default value of
|
|
2240
|
+
# interface field argument in the API schema
|
|
2241
|
+
interface Referencer2 {
|
|
2242
|
+
someField(someArg: Enum = PRIVATE_VALUE): String
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
# Inaccessible enum value can't be referenced by default value of input
|
|
2246
|
+
# object field in the API schema
|
|
2247
|
+
input Referencer3 {
|
|
2248
|
+
someField: Enum = PRIVATE_VALUE
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
# Inaccessible input enum value can't be referenced by default value of
|
|
2252
|
+
# directive argument in the API schema
|
|
2253
|
+
directive @referencer4(someArg: Enum = PRIVATE_VALUE) on INLINE_FRAGMENT
|
|
2254
|
+
|
|
2255
|
+
# Inaccessible enum value can't have a non-inaccessible parent and no
|
|
2256
|
+
# non-inaccessible siblings
|
|
2257
|
+
enum Referencer5 {
|
|
2258
|
+
PRIVATE_VALUE @inaccessible
|
|
2259
|
+
OTHER_PRIVATE_VALUE @inaccessible
|
|
2260
|
+
}
|
|
2261
|
+
`);
|
|
2262
|
+
|
|
2263
|
+
const errorMessages = expectErrors(5, () => {
|
|
2264
|
+
removeInaccessibleElements(schema);
|
|
2265
|
+
});
|
|
2266
|
+
|
|
2267
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
2268
|
+
Array [
|
|
2269
|
+
"Enum value \\"Enum.PRIVATE_VALUE\\" is @inaccessible but is used in the default value of \\"@referencer4(someArg:)\\", which is in the API schema.",
|
|
2270
|
+
"Enum value \\"Enum.PRIVATE_VALUE\\" is @inaccessible but is used in the default value of \\"Referencer1.someField(someArg:)\\", which is in the API schema.",
|
|
2271
|
+
"Enum value \\"Enum.PRIVATE_VALUE\\" is @inaccessible but is used in the default value of \\"Referencer2.someField(someArg:)\\", which is in the API schema.",
|
|
2272
|
+
"Enum value \\"Enum.PRIVATE_VALUE\\" is @inaccessible but is used in the default value of \\"Referencer3.someField\\", which is in the API schema.",
|
|
2273
|
+
"Type \\"Referencer5\\" is in the API schema but all of its values are @inaccessible.",
|
|
2274
|
+
]
|
|
2275
|
+
`);
|
|
2276
|
+
});
|
|
2277
|
+
|
|
2278
|
+
it(`removes @inaccessible directive arguments`, () => {
|
|
2279
|
+
const schema = buildSchema(`
|
|
2280
|
+
${INACCESSIBLE_V02_HEADER}
|
|
2281
|
+
|
|
2282
|
+
type Query {
|
|
2283
|
+
someField: String
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2286
|
+
# Inaccessible (and non-inaccessible) directive argument
|
|
2287
|
+
directive @directive(
|
|
2288
|
+
someArg: String
|
|
2289
|
+
privateArg: String @inaccessible
|
|
2290
|
+
) on QUERY
|
|
2291
|
+
|
|
2292
|
+
# Inaccessible non-nullable directive argument with default
|
|
2293
|
+
directive @directiveDefault(
|
|
2294
|
+
someArg: String
|
|
2295
|
+
privateArg: String! = "default" @inaccessible
|
|
2296
|
+
) on MUTATION
|
|
2297
|
+
`);
|
|
2298
|
+
|
|
2299
|
+
removeInaccessibleElements(schema);
|
|
2300
|
+
schema.validate();
|
|
2301
|
+
expect(schema.elementByCoordinate("@directive(someArg:)")).toBeDefined();
|
|
2302
|
+
expect(
|
|
2303
|
+
schema.elementByCoordinate("@directive(privateArg:)")
|
|
2304
|
+
).toBeUndefined();
|
|
2305
|
+
expect(
|
|
2306
|
+
schema.elementByCoordinate("@directiveDefault(someArg:)")
|
|
2307
|
+
).toBeDefined();
|
|
2308
|
+
expect(
|
|
2309
|
+
schema.elementByCoordinate("@directiveDefault(privateArg:)")
|
|
2310
|
+
).toBeUndefined();
|
|
2311
|
+
});
|
|
2312
|
+
|
|
2313
|
+
it(`fails to remove @inaccessible directive arguments for breaking removals`, () => {
|
|
2314
|
+
const schema = buildSchema(`
|
|
2315
|
+
${INACCESSIBLE_V02_HEADER}
|
|
2316
|
+
|
|
2317
|
+
type Query {
|
|
2318
|
+
someField: String
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
# Inaccessible directive argument
|
|
2322
|
+
directive @directive(privateArg: String @inaccessible) on SUBSCRIPTION
|
|
2323
|
+
|
|
2324
|
+
# Inaccessible directive argument can't be a required field
|
|
2325
|
+
directive @directiveRequired(
|
|
2326
|
+
someArg: String
|
|
2327
|
+
privateArg: String! @inaccessible
|
|
2328
|
+
) on FRAGMENT_DEFINITION
|
|
2329
|
+
`);
|
|
2330
|
+
|
|
2331
|
+
const errorMessages = expectErrors(1, () => {
|
|
2332
|
+
removeInaccessibleElements(schema);
|
|
2333
|
+
});
|
|
2334
|
+
|
|
2335
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
2336
|
+
Array [
|
|
2337
|
+
"Argument \\"@directiveRequired(privateArg:)\\" is @inaccessible but is a required argument of its directive.",
|
|
2338
|
+
]
|
|
2339
|
+
`);
|
|
2340
|
+
});
|
|
2341
|
+
|
|
2342
|
+
it(`handles complex default values`, () => {
|
|
2343
|
+
const schema = buildSchema(`
|
|
2344
|
+
${INACCESSIBLE_V02_HEADER}
|
|
2345
|
+
|
|
2346
|
+
type Query {
|
|
2347
|
+
someField(arg1: [[RootInputObject!]]! = [
|
|
2348
|
+
{
|
|
2349
|
+
foo: {
|
|
2350
|
+
# 2 references (with nesting)
|
|
2351
|
+
privateField: [PRIVATE_VALUE]
|
|
2352
|
+
}
|
|
2353
|
+
bar: SOME_VALUE
|
|
2354
|
+
# 0 references since scalar
|
|
2355
|
+
baz: { privateField: PRIVATE_VALUE }
|
|
2356
|
+
},
|
|
2357
|
+
[{
|
|
2358
|
+
foo: [{
|
|
2359
|
+
someField: "foo"
|
|
2360
|
+
}]
|
|
2361
|
+
# 1 reference
|
|
2362
|
+
bar: PRIVATE_VALUE
|
|
2363
|
+
}]
|
|
2364
|
+
]): String
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
input RootInputObject {
|
|
2368
|
+
foo: [NestedInputObject]
|
|
2369
|
+
bar: Enum!
|
|
2370
|
+
baz: Scalar! = { default: 4 }
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
input NestedInputObject {
|
|
2374
|
+
someField: String
|
|
2375
|
+
privateField: [Enum!] @inaccessible
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
enum Enum {
|
|
2379
|
+
SOME_VALUE
|
|
2380
|
+
PRIVATE_VALUE @inaccessible
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
scalar Scalar
|
|
2384
|
+
`);
|
|
2385
|
+
|
|
2386
|
+
const errorMessages = expectErrors(3, () => {
|
|
2387
|
+
removeInaccessibleElements(schema);
|
|
2388
|
+
});
|
|
2389
|
+
|
|
2390
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
2391
|
+
Array [
|
|
2392
|
+
"Enum value \\"Enum.PRIVATE_VALUE\\" is @inaccessible but is used in the default value of \\"Query.someField(arg1:)\\", which is in the API schema.",
|
|
2393
|
+
"Enum value \\"Enum.PRIVATE_VALUE\\" is @inaccessible but is used in the default value of \\"Query.someField(arg1:)\\", which is in the API schema.",
|
|
2394
|
+
"Input field \\"NestedInputObject.privateField\\" is @inaccessible but is used in the default value of \\"Query.someField(arg1:)\\", which is in the API schema.",
|
|
2395
|
+
]
|
|
2396
|
+
`);
|
|
2397
|
+
});
|
|
2398
|
+
|
|
2399
|
+
// It's not GraphQL-spec-compliant to allow a string for an enum value, but
|
|
2400
|
+
// since we're allowing it, we need to make sure this logic keeps working
|
|
2401
|
+
// until we're allowed to make breaking changes and remove it.
|
|
2402
|
+
it(`handles string enum value in default value`, () => {
|
|
2403
|
+
const schema = buildSchema(`
|
|
2404
|
+
${INACCESSIBLE_V02_HEADER}
|
|
2405
|
+
|
|
2406
|
+
type Query {
|
|
2407
|
+
someField(arg1: Enum! = "PRIVATE_VALUE"): String
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
enum Enum {
|
|
2411
|
+
SOME_VALUE
|
|
2412
|
+
PRIVATE_VALUE @inaccessible
|
|
2413
|
+
}
|
|
2414
|
+
`);
|
|
2415
|
+
|
|
2416
|
+
const errorMessages = expectErrors(1, () => {
|
|
2417
|
+
removeInaccessibleElements(schema);
|
|
2418
|
+
});
|
|
2419
|
+
|
|
2420
|
+
expect(errorMessages).toMatchInlineSnapshot(`
|
|
2421
|
+
Array [
|
|
2422
|
+
"Enum value \\"Enum.PRIVATE_VALUE\\" is @inaccessible but is used in the default value of \\"Query.someField(arg1:)\\", which is in the API schema.",
|
|
2423
|
+
]
|
|
2424
|
+
`);
|
|
350
2425
|
});
|
|
351
2426
|
});
|