@apollo/federation-internals 2.0.0-preview.10 → 2.0.0-preview.13
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 +13 -0
- package/dist/coreSpec.d.ts +1 -1
- package/dist/coreSpec.d.ts.map +1 -1
- package/dist/coreSpec.js +34 -11
- package/dist/coreSpec.js.map +1 -1
- package/dist/definitions.d.ts +6 -2
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +54 -47
- package/dist/definitions.js.map +1 -1
- package/dist/error.d.ts +7 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +15 -3
- package/dist/error.js.map +1 -1
- package/dist/federation.d.ts.map +1 -1
- package/dist/federation.js +3 -2
- package/dist/federation.js.map +1 -1
- package/dist/federationSpec.js +1 -1
- package/dist/federationSpec.js.map +1 -1
- package/dist/inaccessibleSpec.d.ts +7 -3
- package/dist/inaccessibleSpec.d.ts.map +1 -1
- package/dist/inaccessibleSpec.js +622 -32
- package/dist/inaccessibleSpec.js.map +1 -1
- package/dist/schemaUpgrader.js +12 -1
- 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 +3 -0
- 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 +2216 -177
- package/src/__tests__/subgraphValidation.test.ts +2 -2
- package/src/__tests__/values.test.ts +315 -3
- package/src/coreSpec.ts +70 -16
- package/src/definitions.ts +142 -70
- package/src/error.ts +40 -4
- package/src/federation.ts +5 -2
- package/src/federationSpec.ts +2 -2
- package/src/inaccessibleSpec.ts +973 -55
- package/src/schemaUpgrader.ts +21 -1
- package/src/supergraphs.ts +1 -0
- package/src/validate.ts +6 -0
- package/src/values.ts +39 -12
- package/tsconfig.test.tsbuildinfo +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/src/definitions.ts
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
FeatureUrl,
|
|
25
25
|
findCoreSpecVersion,
|
|
26
26
|
isCoreSpecDirectiveApplication,
|
|
27
|
-
|
|
27
|
+
removeAllCoreFeatures,
|
|
28
28
|
} from "./coreSpec";
|
|
29
29
|
import { assert, mapValues, MapWithCachedArrays, setValues } from "./utils";
|
|
30
30
|
import { withDefaultValues, valueEquals, valueToString, valueToAST, variablesInValue, valueFromAST, valueNodeToConstValueNode } from "./values";
|
|
@@ -51,13 +51,21 @@ export const ErrGraphQLValidationFailed = (causes: GraphQLError[], message: stri
|
|
|
51
51
|
causes
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
+
const apiSchemaValidationErrorCode = 'GraphQLAPISchemaValidationFailed';
|
|
55
|
+
|
|
56
|
+
export const ErrGraphQLAPISchemaValidationFailed = (causes: GraphQLError[]) =>
|
|
57
|
+
err(apiSchemaValidationErrorCode, {
|
|
58
|
+
message: 'The supergraph schema failed to produce a valid API schema',
|
|
59
|
+
causes
|
|
60
|
+
});
|
|
61
|
+
|
|
54
62
|
/**
|
|
55
63
|
* Given an error that may have been thrown during schema validation, extract the causes of validation failure.
|
|
56
64
|
* If the error is not a graphQL error, undefined is returned.
|
|
57
65
|
*/
|
|
58
66
|
export function errorCauses(e: Error): GraphQLError[] | undefined {
|
|
59
67
|
if (e instanceof GraphQLErrorExt) {
|
|
60
|
-
if (e.code === validationErrorCode) {
|
|
68
|
+
if (e.code === validationErrorCode || e.code === apiSchemaValidationErrorCode) {
|
|
61
69
|
return ((e as any).causes) as GraphQLError[];
|
|
62
70
|
}
|
|
63
71
|
return [e];
|
|
@@ -508,39 +516,30 @@ export abstract class SchemaElement<TOwnType extends SchemaElement<any, TParent>
|
|
|
508
516
|
}
|
|
509
517
|
|
|
510
518
|
applyDirective<TApplicationArgs extends {[key: string]: any} = {[key: string]: any}>(
|
|
511
|
-
|
|
519
|
+
nameOrDef: DirectiveDefinition<TApplicationArgs> | string,
|
|
512
520
|
args?: TApplicationArgs,
|
|
513
521
|
asFirstDirective: boolean = false,
|
|
514
522
|
): Directive<TOwnType, TApplicationArgs> {
|
|
515
|
-
let
|
|
516
|
-
if (
|
|
517
|
-
this.checkUpdate(
|
|
518
|
-
|
|
519
|
-
if (
|
|
520
|
-
|
|
523
|
+
let name: string;
|
|
524
|
+
if (typeof nameOrDef === 'string') {
|
|
525
|
+
this.checkUpdate();
|
|
526
|
+
const def = this.schema().directive(nameOrDef) ?? this.schema().blueprint.onMissingDirectiveDefinition(this.schema(), nameOrDef, args);
|
|
527
|
+
if (!def) {
|
|
528
|
+
throw this.schema().blueprint.onGraphQLJSValidationError(
|
|
529
|
+
this.schema(),
|
|
530
|
+
new GraphQLError(`Unknown directive "@${nameOrDef}".`)
|
|
531
|
+
);
|
|
521
532
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
if (typeof nameOrDefOrDirective === 'string') {
|
|
525
|
-
this.checkUpdate();
|
|
526
|
-
const def = this.schema().directive(nameOrDefOrDirective) ?? this.schema().blueprint.onMissingDirectiveDefinition(this.schema(), nameOrDefOrDirective, args);
|
|
527
|
-
if (!def) {
|
|
528
|
-
throw this.schema().blueprint.onGraphQLJSValidationError(
|
|
529
|
-
this.schema(),
|
|
530
|
-
new GraphQLError(`Unknown directive "@${nameOrDefOrDirective}".`)
|
|
531
|
-
);
|
|
532
|
-
}
|
|
533
|
-
if (Array.isArray(def)) {
|
|
534
|
-
throw ErrGraphQLValidationFailed(def);
|
|
535
|
-
}
|
|
536
|
-
name = nameOrDefOrDirective;
|
|
537
|
-
} else {
|
|
538
|
-
this.checkUpdate(nameOrDefOrDirective);
|
|
539
|
-
name = nameOrDefOrDirective.name;
|
|
533
|
+
if (Array.isArray(def)) {
|
|
534
|
+
throw ErrGraphQLValidationFailed(def);
|
|
540
535
|
}
|
|
541
|
-
|
|
542
|
-
|
|
536
|
+
name = nameOrDef;
|
|
537
|
+
} else {
|
|
538
|
+
this.checkUpdate(nameOrDef);
|
|
539
|
+
name = nameOrDef.name;
|
|
543
540
|
}
|
|
541
|
+
const toAdd = new Directive<TOwnType, TApplicationArgs>(name, args ?? Object.create(null));
|
|
542
|
+
Element.prototype['setParent'].call(toAdd, this);
|
|
544
543
|
// TODO: we should typecheck arguments or our TApplicationArgs business is just a lie.
|
|
545
544
|
if (asFirstDirective) {
|
|
546
545
|
this._appliedDirectives.unshift(toAdd);
|
|
@@ -724,7 +723,7 @@ abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSche
|
|
|
724
723
|
/**
|
|
725
724
|
* Removes this type definition from its parent schema.
|
|
726
725
|
*
|
|
727
|
-
* After calling this method, this type will be "detached": it
|
|
726
|
+
* After calling this method, this type will be "detached": it will have no parent, schema, fields,
|
|
728
727
|
* values, directives, etc...
|
|
729
728
|
*
|
|
730
729
|
* Note that it is always allowed to remove a type, but this may make a valid schema
|
|
@@ -740,15 +739,18 @@ abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSche
|
|
|
740
739
|
}
|
|
741
740
|
this.checkRemoval();
|
|
742
741
|
this.onModification();
|
|
743
|
-
this.
|
|
744
|
-
Schema.prototype['removeTypeInternal'].call(this._parent, this);
|
|
745
|
-
this.removeAppliedDirectives();
|
|
742
|
+
// Remove this type's children.
|
|
746
743
|
this.sourceAST = undefined;
|
|
744
|
+
this.removeAppliedDirectives();
|
|
745
|
+
this.removeInnerElements();
|
|
746
|
+
// Remove this type's references.
|
|
747
747
|
const toReturn = setValues(this._referencers).map(r => {
|
|
748
748
|
SchemaElement.prototype['removeTypeReferenceInternal'].call(r, this);
|
|
749
749
|
return r;
|
|
750
750
|
});
|
|
751
751
|
this._referencers.clear();
|
|
752
|
+
// Remove this type from its parent schema.
|
|
753
|
+
Schema.prototype['removeTypeInternal'].call(this._parent, this);
|
|
752
754
|
this._parent = undefined;
|
|
753
755
|
return toReturn;
|
|
754
756
|
}
|
|
@@ -935,9 +937,12 @@ export class CoreFeature {
|
|
|
935
937
|
}
|
|
936
938
|
|
|
937
939
|
isFeatureDefinition(element: NamedType | DirectiveDefinition): boolean {
|
|
940
|
+
const importName = element.kind === 'DirectiveDefinition'
|
|
941
|
+
? '@' + element.name
|
|
942
|
+
: element.name;
|
|
938
943
|
return element.name.startsWith(this.nameInSchema + '__')
|
|
939
944
|
|| (element.kind === 'DirectiveDefinition' && element.name === this.nameInSchema)
|
|
940
|
-
|| !!this.imports.find((i) =>
|
|
945
|
+
|| !!this.imports.find((i) => importName === (i.as ?? i.name));
|
|
941
946
|
}
|
|
942
947
|
|
|
943
948
|
directiveNameInSchema(name: string): string {
|
|
@@ -1152,13 +1157,7 @@ export class Schema {
|
|
|
1152
1157
|
|
|
1153
1158
|
const apiSchema = this.clone();
|
|
1154
1159
|
removeInaccessibleElements(apiSchema);
|
|
1155
|
-
|
|
1156
|
-
if (coreFeatures) {
|
|
1157
|
-
// Note that core being a feature itself, this will remove core itself and mark apiSchema as 'not core'
|
|
1158
|
-
for (const coreFeature of coreFeatures.allFeatures()) {
|
|
1159
|
-
removeFeatureElements(apiSchema, coreFeature);
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1160
|
+
removeAllCoreFeatures(apiSchema);
|
|
1162
1161
|
assert(!apiSchema.isCoreSchema(), "The API schema shouldn't be a core schema")
|
|
1163
1162
|
apiSchema.validate();
|
|
1164
1163
|
this.apiSchema = apiSchema;
|
|
@@ -1530,11 +1529,11 @@ export class SchemaDefinition extends SchemaElement<SchemaDefinition, Schema> {
|
|
|
1530
1529
|
}
|
|
1531
1530
|
|
|
1532
1531
|
applyDirective<TApplicationArgs extends {[key: string]: any} = {[key: string]: any}>(
|
|
1533
|
-
|
|
1532
|
+
nameOrDef: DirectiveDefinition<TApplicationArgs> | string,
|
|
1534
1533
|
args?: TApplicationArgs,
|
|
1535
1534
|
asFirstDirective: boolean = false,
|
|
1536
1535
|
): Directive<SchemaDefinition, TApplicationArgs> {
|
|
1537
|
-
const applied = super.applyDirective(
|
|
1536
|
+
const applied = super.applyDirective(nameOrDef, args, asFirstDirective) as Directive<SchemaDefinition, TApplicationArgs>;
|
|
1538
1537
|
const schema = this.schema();
|
|
1539
1538
|
const coreFeatures = schema.coreFeatures;
|
|
1540
1539
|
if (isCoreSpecDirectiveApplication(applied)) {
|
|
@@ -2363,23 +2362,36 @@ export class FieldDefinition<TParent extends CompositeType> extends NamedSchemaE
|
|
|
2363
2362
|
/**
|
|
2364
2363
|
* Removes this field definition from its parent type.
|
|
2365
2364
|
*
|
|
2366
|
-
* After calling this method, this field definition will be "detached": it
|
|
2367
|
-
* arguments or directives.
|
|
2365
|
+
* After calling this method, this field definition will be "detached": it will have no parent, schema, type,
|
|
2366
|
+
* arguments, or directives.
|
|
2368
2367
|
*/
|
|
2369
2368
|
remove(): never[] {
|
|
2370
2369
|
if (!this._parent) {
|
|
2371
2370
|
return [];
|
|
2372
2371
|
}
|
|
2372
|
+
this.checkRemoval();
|
|
2373
2373
|
this.onModification();
|
|
2374
|
-
this.
|
|
2374
|
+
// Remove this field's children.
|
|
2375
|
+
this.sourceAST = undefined;
|
|
2375
2376
|
this.type = undefined;
|
|
2376
|
-
this.
|
|
2377
|
+
this.removeAppliedDirectives();
|
|
2377
2378
|
for (const arg of this.arguments()) {
|
|
2378
2379
|
arg.remove();
|
|
2379
2380
|
}
|
|
2381
|
+
// Note that we don't track field references outside of parents, so no
|
|
2382
|
+
// removal needed there.
|
|
2383
|
+
//
|
|
2384
|
+
// TODO: One could consider interface fields as references to implementing
|
|
2385
|
+
// object/interface fields, in the sense that removing an implementing
|
|
2386
|
+
// object/interface field breaks the validity of the implementing
|
|
2387
|
+
// interface field. Being aware that an object/interface field is being
|
|
2388
|
+
// referenced in such a way would be useful for understanding breakages
|
|
2389
|
+
// that need to be resolved as a consequence of removal.
|
|
2390
|
+
//
|
|
2391
|
+
// Remove this field from its parent object/interface type.
|
|
2380
2392
|
FieldBasedType.prototype['removeFieldInternal'].call(this._parent, this);
|
|
2381
2393
|
this._parent = undefined;
|
|
2382
|
-
|
|
2394
|
+
this._extension = undefined;
|
|
2383
2395
|
return [];
|
|
2384
2396
|
}
|
|
2385
2397
|
|
|
@@ -2442,21 +2454,38 @@ export class InputFieldDefinition extends NamedSchemaElementWithType<InputType,
|
|
|
2442
2454
|
}
|
|
2443
2455
|
|
|
2444
2456
|
/**
|
|
2445
|
-
* Removes this field definition from its parent type.
|
|
2457
|
+
* Removes this input field definition from its parent type.
|
|
2446
2458
|
*
|
|
2447
|
-
* After calling this method, this field definition will be "detached": it
|
|
2448
|
-
*
|
|
2459
|
+
* After calling this method, this input field definition will be "detached": it will have no parent, schema,
|
|
2460
|
+
* type, default value, or directives.
|
|
2449
2461
|
*/
|
|
2450
2462
|
remove(): never[] {
|
|
2451
2463
|
if (!this._parent) {
|
|
2452
2464
|
return [];
|
|
2453
2465
|
}
|
|
2466
|
+
this.checkRemoval();
|
|
2454
2467
|
this.onModification();
|
|
2468
|
+
// Remove this input field's children.
|
|
2469
|
+
this.sourceAST = undefined;
|
|
2470
|
+
this.type = undefined;
|
|
2471
|
+
this.defaultValue = undefined;
|
|
2455
2472
|
this.removeAppliedDirectives();
|
|
2473
|
+
// Note that we don't track input field references outside of parents, so no
|
|
2474
|
+
// removal needed there.
|
|
2475
|
+
//
|
|
2476
|
+
// TODO: One could consider default values (in field arguments, input
|
|
2477
|
+
// fields, or directive definitions) as references to input fields they
|
|
2478
|
+
// use, in the sense that removing the input field breaks the validity of
|
|
2479
|
+
// the default value. Being aware that an input field is being referenced
|
|
2480
|
+
// in such a way would be useful for understanding breakages that need to
|
|
2481
|
+
// be resolved as a consequence of removal. (The reference is indirect
|
|
2482
|
+
// though, as input field usages are currently represented as strings
|
|
2483
|
+
// within GraphQL values).
|
|
2484
|
+
//
|
|
2485
|
+
// Remove this input field from its parent input object type.
|
|
2456
2486
|
InputObjectType.prototype['removeFieldInternal'].call(this._parent, this);
|
|
2457
2487
|
this._parent = undefined;
|
|
2458
|
-
this.
|
|
2459
|
-
// Fields have nothing that can reference them outside of their parents
|
|
2488
|
+
this._extension = undefined;
|
|
2460
2489
|
return [];
|
|
2461
2490
|
}
|
|
2462
2491
|
|
|
@@ -2501,23 +2530,39 @@ export class ArgumentDefinition<TParent extends FieldDefinition<any> | Directive
|
|
|
2501
2530
|
/**
|
|
2502
2531
|
* Removes this argument definition from its parent element (field or directive).
|
|
2503
2532
|
*
|
|
2504
|
-
* After calling this method, this argument definition will be "detached": it
|
|
2505
|
-
* default value or directives.
|
|
2533
|
+
* After calling this method, this argument definition will be "detached": it will have no parent, schema, type,
|
|
2534
|
+
* default value, or directives.
|
|
2506
2535
|
*/
|
|
2507
2536
|
remove(): never[] {
|
|
2508
2537
|
if (!this._parent) {
|
|
2509
2538
|
return [];
|
|
2510
2539
|
}
|
|
2540
|
+
this.checkRemoval();
|
|
2511
2541
|
this.onModification();
|
|
2542
|
+
// Remove this argument's children.
|
|
2543
|
+
this.sourceAST = undefined;
|
|
2544
|
+
this.type = undefined;
|
|
2545
|
+
this.defaultValue = undefined;
|
|
2512
2546
|
this.removeAppliedDirectives();
|
|
2547
|
+
// Note that we don't track argument references outside of parents, so no
|
|
2548
|
+
// removal needed there.
|
|
2549
|
+
//
|
|
2550
|
+
// TODO: One could consider the arguments of directive applications as
|
|
2551
|
+
// references to the arguments of directive definitions, in the sense that
|
|
2552
|
+
// removing a directive definition argument can break the validity of the
|
|
2553
|
+
// directive application. Being aware that a directive definition argument
|
|
2554
|
+
// is being referenced in such a way would be useful for understanding
|
|
2555
|
+
// breakages that need to be resolved as a consequence of removal. (You
|
|
2556
|
+
// could make a similar claim about interface field arguments being
|
|
2557
|
+
// references to object field arguments.)
|
|
2558
|
+
//
|
|
2559
|
+
// Remove this argument from its parent field or directive definition.
|
|
2513
2560
|
if (this._parent instanceof FieldDefinition) {
|
|
2514
2561
|
FieldDefinition.prototype['removeArgumentInternal'].call(this._parent, this.name);
|
|
2515
2562
|
} else {
|
|
2516
2563
|
DirectiveDefinition.prototype['removeArgumentInternal'].call(this._parent, this.name);
|
|
2517
2564
|
}
|
|
2518
2565
|
this._parent = undefined;
|
|
2519
|
-
this.type = undefined;
|
|
2520
|
-
this.defaultValue = undefined;
|
|
2521
2566
|
return [];
|
|
2522
2567
|
}
|
|
2523
2568
|
|
|
@@ -2558,24 +2603,36 @@ export class EnumValue extends NamedSchemaElement<EnumValue, EnumType, never> {
|
|
|
2558
2603
|
}
|
|
2559
2604
|
|
|
2560
2605
|
/**
|
|
2561
|
-
* Removes this
|
|
2606
|
+
* Removes this enum value definition from its parent type.
|
|
2562
2607
|
*
|
|
2563
|
-
* After calling this method, this
|
|
2564
|
-
* arguments or directives.
|
|
2608
|
+
* After calling this method, this enum value definition will be "detached": it will have no parent, schema, type,
|
|
2609
|
+
* arguments, or directives.
|
|
2565
2610
|
*/
|
|
2566
2611
|
remove(): never[] {
|
|
2567
2612
|
if (!this._parent) {
|
|
2568
2613
|
return [];
|
|
2569
2614
|
}
|
|
2615
|
+
this.checkRemoval();
|
|
2570
2616
|
this.onModification();
|
|
2617
|
+
// Remove this enum value's children.
|
|
2618
|
+
this.sourceAST = undefined;
|
|
2571
2619
|
this.removeAppliedDirectives();
|
|
2620
|
+
// Note that we don't track enum value references outside of parents, so no
|
|
2621
|
+
// removal needed there.
|
|
2622
|
+
//
|
|
2623
|
+
// TODO: One could consider default values (in field arguments, input
|
|
2624
|
+
// fields, or directive definitions) as references to enum values they
|
|
2625
|
+
// use, in the sense that removing the enum value breaks the validity of
|
|
2626
|
+
// the default value. Being aware that an enum value is being referenced
|
|
2627
|
+
// in such a way would be useful for understanding breakages that need to
|
|
2628
|
+
// be resolved as a consequence of removal. (The reference is indirect
|
|
2629
|
+
// though, as enum value usages are currently represented as strings
|
|
2630
|
+
// within GraphQL values).
|
|
2631
|
+
//
|
|
2632
|
+
// Remove this enum value from its parent enum type.
|
|
2572
2633
|
EnumType.prototype['removeValueInternal'].call(this._parent, this);
|
|
2573
2634
|
this._parent = undefined;
|
|
2574
|
-
|
|
2575
|
-
// TODO: that's actually only semi-true if you include arguments, because default values in args and concrete directive applications can
|
|
2576
|
-
// indirectly refer to enum value. It's indirect though as we currently keep enum value as string in values. That said, it would
|
|
2577
|
-
// probably be really nice to be able to known if an enum value is used or not, rather then removing it and not knowing if we broke
|
|
2578
|
-
// something).
|
|
2635
|
+
this._extension = undefined;
|
|
2579
2636
|
return [];
|
|
2580
2637
|
}
|
|
2581
2638
|
|
|
@@ -2705,22 +2762,35 @@ export class DirectiveDefinition<TApplicationArgs extends {[key: string]: any} =
|
|
|
2705
2762
|
assert(false, `Directive definition ${this} can't reference other types (it's arguments can); shouldn't be asked to remove reference to ${type}`);
|
|
2706
2763
|
}
|
|
2707
2764
|
|
|
2765
|
+
/**
|
|
2766
|
+
* Removes this directive definition from its parent schema.
|
|
2767
|
+
*
|
|
2768
|
+
* After calling this method, this directive definition will be "detached": it will have no parent, schema, or
|
|
2769
|
+
* arguments.
|
|
2770
|
+
*/
|
|
2708
2771
|
remove(): Directive[] {
|
|
2709
2772
|
if (!this._parent) {
|
|
2710
2773
|
return [];
|
|
2711
2774
|
}
|
|
2775
|
+
this.checkRemoval();
|
|
2712
2776
|
this.onModification();
|
|
2713
|
-
|
|
2714
|
-
this.
|
|
2777
|
+
// Remove this directive definition's children.
|
|
2778
|
+
this.sourceAST = undefined;
|
|
2715
2779
|
assert(this._appliedDirectives.length === 0, "Directive definition should not have directive applied to it");
|
|
2716
2780
|
for (const arg of this.arguments()) {
|
|
2717
2781
|
arg.remove();
|
|
2718
2782
|
}
|
|
2719
|
-
//
|
|
2720
|
-
//
|
|
2721
|
-
//
|
|
2783
|
+
// Remove this directive definition's references.
|
|
2784
|
+
//
|
|
2785
|
+
// Note that while a directive application references its definition, it
|
|
2786
|
+
// doesn't store a link to that definition. Instead, we fetch the definition
|
|
2787
|
+
// from the schema when requested. So we don't have to do anything on the
|
|
2788
|
+
// referencers other than clear them (and return the pre-cleared set).
|
|
2722
2789
|
const toReturn = setValues(this._referencers);
|
|
2723
2790
|
this._referencers.clear();
|
|
2791
|
+
// Remove this directive definition from its parent schema.
|
|
2792
|
+
Schema.prototype['removeDirectiveInternal'].call(this._parent, this);
|
|
2793
|
+
this._parent = undefined;
|
|
2724
2794
|
return toReturn;
|
|
2725
2795
|
}
|
|
2726
2796
|
|
|
@@ -2886,10 +2956,12 @@ export class Directive<
|
|
|
2886
2956
|
if (!this._parent) {
|
|
2887
2957
|
return false;
|
|
2888
2958
|
}
|
|
2959
|
+
// Remove this directive application's reference to its definition.
|
|
2889
2960
|
const definition = this.definition;
|
|
2890
2961
|
if (definition && this.isAttachedToSchemaElement()) {
|
|
2891
2962
|
DirectiveDefinition.prototype['removeReferencer'].call(definition, this as Directive<SchemaElement<any, any>>);
|
|
2892
2963
|
}
|
|
2964
|
+
// Remove this directive application from its parent schema element.
|
|
2893
2965
|
const parentDirectives = this._parent.appliedDirectives as Directive<TParent>[];
|
|
2894
2966
|
const index = parentDirectives.indexOf(this);
|
|
2895
2967
|
assert(index >= 0, () => `Directive ${this} lists ${this._parent} as parent, but that parent doesn't list it as applied directive`);
|
package/src/error.ts
CHANGED
|
@@ -346,7 +346,37 @@ const LINK_IMPORT_NAME_MISMATCH = makeCodeDefinition(
|
|
|
346
346
|
|
|
347
347
|
const REFERENCED_INACCESSIBLE = makeCodeDefinition(
|
|
348
348
|
'REFERENCED_INACCESSIBLE',
|
|
349
|
-
'An element is marked as @inaccessible but is referenced by
|
|
349
|
+
'An element is marked as @inaccessible but is referenced by an element visible in the API schema.'
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
const DEFAULT_VALUE_USES_INACCESSIBLE = makeCodeDefinition(
|
|
353
|
+
'DEFAULT_VALUE_USES_INACCESSIBLE',
|
|
354
|
+
'An element is marked as @inaccessible but is used in the default value of an element visible in the API schema.'
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
const QUERY_ROOT_TYPE_INACCESSIBLE = makeCodeDefinition(
|
|
358
|
+
'QUERY_ROOT_TYPE_INACCESSIBLE',
|
|
359
|
+
'An element is marked as @inaccessible but is the query root type, which must be visible in the API schema.'
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
const REQUIRED_INACCESSIBLE = makeCodeDefinition(
|
|
363
|
+
'REQUIRED_INACCESSIBLE',
|
|
364
|
+
'An element is marked as @inaccessible but is required by an element visible in the API schema.'
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
const IMPLEMENTED_BY_INACCESSIBLE = makeCodeDefinition(
|
|
368
|
+
'IMPLEMENTED_BY_INACCESSIBLE',
|
|
369
|
+
'An element is marked as @inaccessible but implements an element visible in the API schema.'
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
const DISALLOWED_INACCESSIBLE = makeCodeDefinition(
|
|
373
|
+
'DISALLOWED_INACCESSIBLE',
|
|
374
|
+
'An element is marked as @inaccessible that is not allowed to be @inaccessible.'
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
const ONLY_INACCESSIBLE_CHILDREN = makeCodeDefinition(
|
|
378
|
+
'ONLY_INACCESSIBLE_CHILDREN',
|
|
379
|
+
'A type visible in the API schema has only @inaccessible children.'
|
|
350
380
|
);
|
|
351
381
|
|
|
352
382
|
const REQUIRED_INPUT_FIELD_MISSING_IN_SOME_SUBGRAPH = makeCodeDefinition(
|
|
@@ -364,8 +394,8 @@ const EMPTY_MERGED_INPUT_TYPE = makeCodeDefinition(
|
|
|
364
394
|
'An input object type has no field common to all the subgraphs that define the type. Merging that type would result in an invalid empty input object type.'
|
|
365
395
|
);
|
|
366
396
|
|
|
367
|
-
const
|
|
368
|
-
'
|
|
397
|
+
const ENUM_VALUE_MISMATCH = makeCodeDefinition(
|
|
398
|
+
'ENUM_VALUE_MISMATCH',
|
|
369
399
|
'An enum type that is used as both an input and output type has a value that is not defined in all the subgraphs that define the enum type.'
|
|
370
400
|
);
|
|
371
401
|
|
|
@@ -451,10 +481,16 @@ export const ERRORS = {
|
|
|
451
481
|
INVALID_LINK_DIRECTIVE_USAGE,
|
|
452
482
|
LINK_IMPORT_NAME_MISMATCH,
|
|
453
483
|
REFERENCED_INACCESSIBLE,
|
|
484
|
+
DEFAULT_VALUE_USES_INACCESSIBLE,
|
|
485
|
+
QUERY_ROOT_TYPE_INACCESSIBLE,
|
|
486
|
+
REQUIRED_INACCESSIBLE,
|
|
487
|
+
DISALLOWED_INACCESSIBLE,
|
|
488
|
+
IMPLEMENTED_BY_INACCESSIBLE,
|
|
489
|
+
ONLY_INACCESSIBLE_CHILDREN,
|
|
454
490
|
REQUIRED_ARGUMENT_MISSING_IN_SOME_SUBGRAPH,
|
|
455
491
|
REQUIRED_INPUT_FIELD_MISSING_IN_SOME_SUBGRAPH,
|
|
456
492
|
EMPTY_MERGED_INPUT_TYPE,
|
|
457
|
-
|
|
493
|
+
ENUM_VALUE_MISMATCH,
|
|
458
494
|
EMPTY_MERGED_ENUM_TYPE,
|
|
459
495
|
SATISFIABILITY_ERROR,
|
|
460
496
|
OVERRIDE_COLLISION_WITH_ANOTHER_DIRECTIVE,
|
package/src/federation.ts
CHANGED
|
@@ -45,6 +45,7 @@ import { KnownTypeNamesInFederationRule } from "./validation/KnownTypeNamesInFed
|
|
|
45
45
|
import { buildSchema, buildSchemaFromAST } from "./buildSchema";
|
|
46
46
|
import { parseSelectionSet, selectionOfElement, SelectionSet } from './operations';
|
|
47
47
|
import { TAG_VERSIONS } from "./tagSpec";
|
|
48
|
+
import { INACCESSIBLE_VERSIONS } from "./inaccessibleSpec";
|
|
48
49
|
import {
|
|
49
50
|
errorCodeDef,
|
|
50
51
|
ErrorCodeDefinition,
|
|
@@ -79,10 +80,10 @@ import {
|
|
|
79
80
|
import { defaultPrintOptions, PrintOptions as PrintOptions, printSchema } from "./print";
|
|
80
81
|
import { createObjectTypeSpecification, createScalarTypeSpecification, createUnionTypeSpecification } from "./directiveAndTypeSpecification";
|
|
81
82
|
import { didYouMean, suggestionList } from "./suggestions";
|
|
82
|
-
import { inaccessibleDirectiveSpec } from "./inaccessibleSpec";
|
|
83
83
|
|
|
84
84
|
const linkSpec = LINK_VERSIONS.latest();
|
|
85
85
|
const tagSpec = TAG_VERSIONS.latest();
|
|
86
|
+
const inaccessibleSpec = INACCESSIBLE_VERSIONS.latest();
|
|
86
87
|
const federationSpec = FEDERATION_VERSIONS.latest();
|
|
87
88
|
|
|
88
89
|
// We don't let user use this as a subgraph name. That allows us to use it in `query graphs` to name the source of roots
|
|
@@ -565,7 +566,9 @@ export class FederationMetadata {
|
|
|
565
566
|
}
|
|
566
567
|
|
|
567
568
|
inaccessibleDirective(): DirectiveDefinition<{}> {
|
|
568
|
-
return this.getFederationDirective(
|
|
569
|
+
return this.getFederationDirective(
|
|
570
|
+
inaccessibleSpec.inaccessibleDirectiveSpec.name
|
|
571
|
+
);
|
|
569
572
|
}
|
|
570
573
|
|
|
571
574
|
allFederationDirectives(): DirectiveDefinition[] {
|
package/src/federationSpec.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { assert } from "./utils";
|
|
|
14
14
|
import { TAG_VERSIONS } from "./tagSpec";
|
|
15
15
|
import { federationMetadata } from "./federation";
|
|
16
16
|
import { registerKnownFeature } from "./knownCoreFeatures";
|
|
17
|
-
import {
|
|
17
|
+
import { INACCESSIBLE_VERSIONS } from "./inaccessibleSpec";
|
|
18
18
|
|
|
19
19
|
export const federationIdentity = 'https://specs.apollo.dev/federation';
|
|
20
20
|
|
|
@@ -91,7 +91,7 @@ function fieldSetType(schema: Schema): InputType {
|
|
|
91
91
|
|
|
92
92
|
export const FEDERATION2_ONLY_SPEC_DIRECTIVES = [
|
|
93
93
|
shareableDirectiveSpec,
|
|
94
|
-
inaccessibleDirectiveSpec,
|
|
94
|
+
INACCESSIBLE_VERSIONS.latest().inaccessibleDirectiveSpec,
|
|
95
95
|
overrideDirectiveSpec,
|
|
96
96
|
];
|
|
97
97
|
|