@apollo/federation-internals
Advanced tools
Comparing version 2.1.4 to 2.2.0
@@ -5,3 +5,10 @@ # CHANGELOG for `@apollo/federation-internals` | ||
## 2.2.0 | ||
- Preserve default values of input object fields [PR #2218](https://github.com/apollographql/federation/pull/2218). | ||
- Provide support for marking @external on object type [PR #2214](https://github.com/apollographql/federation/pull/2214) | ||
- Drop support for node12 [PR #2202](https://github.com/apollographql/federation/pull/2202) | ||
- Correctly reject field names starting with `__` [PR #2237](https://github.com/apollographql/federation/pull/2237). | ||
- Preserve default values of input object fields [PR #2218](https://github.com/apollographql/federation/pull/2218). | ||
## 2.1.4 | ||
@@ -8,0 +15,0 @@ |
@@ -8,2 +8,3 @@ "use strict"; | ||
const error_1 = require("./error"); | ||
const introspection_1 = require("./introspection"); | ||
function buildValue(value) { | ||
@@ -90,2 +91,5 @@ return value ? (0, values_1.valueFromASTUntyped)(value) : undefined; | ||
case 'InputObjectTypeDefinition': | ||
if (introspection_1.introspectionTypeNames.includes(definitionNode.name.value)) { | ||
continue; | ||
} | ||
typeDefinitions.push(definitionNode); | ||
@@ -107,2 +111,5 @@ let type = schema.type(definitionNode.name.value); | ||
case 'InputObjectTypeExtension': | ||
if (introspection_1.introspectionTypeNames.includes(definitionNode.name.value)) { | ||
continue; | ||
} | ||
typeExtensions.push(definitionNode); | ||
@@ -109,0 +116,0 @@ const existing = schema.type(definitionNode.name.value); |
@@ -94,2 +94,3 @@ import { ASTNode, GraphQLError, GraphQLErrorOptions, GraphQLFormattedError } from "graphql"; | ||
INVALID_FIELD_SHARING: ErrorCodeDefinition; | ||
INVALID_SHAREABLE_USAGE: ErrorCodeDefinition; | ||
INVALID_LINK_DIRECTIVE_USAGE: ErrorCodeDefinition; | ||
@@ -96,0 +97,0 @@ INVALID_LINK_IDENTIFIER: ErrorCodeDefinition; |
@@ -177,2 +177,3 @@ "use strict"; | ||
const INVALID_FIELD_SHARING = makeCodeDefinition('INVALID_FIELD_SHARING', 'A field that is non-shareable in at least one subgraph is resolved by multiple subgraphs.'); | ||
const INVALID_SHAREABLE_USAGE = makeCodeDefinition('INVALID_SHAREABLE_USAGE', 'The `@shareable` federation directive is used in an invalid way.', { addedIn: '2.1.2' }); | ||
const INVALID_LINK_DIRECTIVE_USAGE = makeCodeDefinition('INVALID_LINK_DIRECTIVE_USAGE', 'An application of the @link directive is invalid/does not respect the specification.'); | ||
@@ -256,2 +257,3 @@ const INVALID_LINK_IDENTIFIER = makeCodeDefinition('INVALID_LINK_IDENTIFIER', 'A url/version for a @link feature is invalid/does not respect the specification.', { addedIn: '2.1.0' }); | ||
INVALID_FIELD_SHARING, | ||
INVALID_SHAREABLE_USAGE, | ||
INVALID_LINK_DIRECTIVE_USAGE, | ||
@@ -258,0 +260,0 @@ INVALID_LINK_IDENTIFIER, |
@@ -235,5 +235,9 @@ "use strict"; | ||
const fieldBaseType = (0, definitions_1.baseType)(field.type); | ||
const isShareable = (0, definitions_1.isObjectType)(type) && subgraphs.values().filter((s) => s.schema.type(type.name)).length > 1; | ||
for (const subgraph of subgraphs) { | ||
if (subgraph.schema.type(fieldBaseType.name)) { | ||
addSubgraphField(field, subgraph); | ||
const subgraphField = addSubgraphField(field, subgraph); | ||
if (subgraphField && isShareable) { | ||
subgraphField.applyDirective(subgraph.metadata().shareableDirective()); | ||
} | ||
} | ||
@@ -250,2 +254,7 @@ } | ||
else { | ||
const isShareable = (0, definitions_1.isObjectType)(type) | ||
&& fieldApplications.filter((application) => { | ||
const args = application.arguments(); | ||
return !args.external && !args.usedOverridden; | ||
}).length > 1; | ||
for (const application of fieldApplications) { | ||
@@ -274,2 +283,5 @@ const args = application.arguments(); | ||
} | ||
if (isShareable && !args.external && !args.usedOverridden) { | ||
subgraphField.applyDirective(subgraph.metadata().shareableDirective()); | ||
} | ||
} | ||
@@ -438,3 +450,5 @@ } | ||
: copyType(supergraphField.type, subgraph.schema, subgraph.name); | ||
return subgraphType.addField(supergraphField.name, copiedType); | ||
const field = subgraphType.addField(supergraphField.name, copiedType); | ||
field.defaultValue = supergraphField.defaultValue; | ||
return field; | ||
} | ||
@@ -441,0 +455,0 @@ else { |
@@ -82,3 +82,3 @@ import { CompositeType, CoreFeature, Directive, DirectiveDefinition, FieldDefinition, InputFieldDefinition, InterfaceType, NamedType, ObjectType, ScalarType, Schema, SchemaBlueprint, SchemaConfig, SchemaElement, UnionType } from "./definitions"; | ||
export declare function setSchemaAsFed2Subgraph(schema: Schema): void; | ||
export declare const FEDERATION2_LINK_WTH_FULL_IMPORTS = "@link(url: \"https://specs.apollo.dev/federation/v2.1\", import: [\"@key\", \"@requires\", \"@provides\", \"@external\", \"@tag\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@composeDirective\"])"; | ||
export declare const FEDERATION2_LINK_WITH_FULL_IMPORTS = "@link(url: \"https://specs.apollo.dev/federation/v2.2\", import: [\"@key\", \"@requires\", \"@provides\", \"@external\", \"@tag\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@composeDirective\"])"; | ||
export declare function asFed2SubgraphDocument(document: DocumentNode): DocumentNode; | ||
@@ -85,0 +85,0 @@ export declare function printSubgraphNames(names: string[]): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.removeInactiveProvidesAndRequires = exports.addSubgraphToError = exports.addSubgraphToASTNode = exports.Subgraph = exports.FEDERATION_OPERATION_FIELDS = exports.entitiesFieldName = exports.serviceFieldName = exports.FEDERATION_OPERATION_TYPES = exports.entityTypeSpec = exports.serviceTypeSpec = exports.anyTypeSpec = exports.Subgraphs = exports.subgraphsFromServiceList = exports.collectTargetFields = exports.parseFieldSetArgument = exports.newEmptyFederation2Schema = exports.buildSubgraph = exports.isEntityType = exports.isFederationField = exports.isFederationSubgraphSchema = exports.federationMetadata = exports.printSubgraphNames = exports.asFed2SubgraphDocument = exports.FEDERATION2_LINK_WTH_FULL_IMPORTS = exports.setSchemaAsFed2Subgraph = exports.FederationBlueprint = exports.FederationMetadata = exports.collectUsedFields = exports.FEDERATION_UNNAMED_SUBGRAPH_NAME = exports.FEDERATION_RESERVED_SUBGRAPH_NAME = void 0; | ||
exports.removeInactiveProvidesAndRequires = exports.addSubgraphToError = exports.addSubgraphToASTNode = exports.Subgraph = exports.FEDERATION_OPERATION_FIELDS = exports.entitiesFieldName = exports.serviceFieldName = exports.FEDERATION_OPERATION_TYPES = exports.entityTypeSpec = exports.serviceTypeSpec = exports.anyTypeSpec = exports.Subgraphs = exports.subgraphsFromServiceList = exports.collectTargetFields = exports.parseFieldSetArgument = exports.newEmptyFederation2Schema = exports.buildSubgraph = exports.isEntityType = exports.isFederationField = exports.isFederationSubgraphSchema = exports.federationMetadata = exports.printSubgraphNames = exports.asFed2SubgraphDocument = exports.FEDERATION2_LINK_WITH_FULL_IMPORTS = exports.setSchemaAsFed2Subgraph = exports.FederationBlueprint = exports.FederationMetadata = exports.collectUsedFields = exports.FEDERATION_UNNAMED_SUBGRAPH_NAME = exports.FEDERATION_RESERVED_SUBGRAPH_NAME = void 0; | ||
const definitions_1 = require("./definitions"); | ||
@@ -12,3 +12,2 @@ const utils_1 = require("./utils"); | ||
const tagSpec_1 = require("./tagSpec"); | ||
const inaccessibleSpec_1 = require("./inaccessibleSpec"); | ||
const error_1 = require("./error"); | ||
@@ -23,3 +22,2 @@ const precompute_1 = require("./precompute"); | ||
const tagSpec = tagSpec_1.TAG_VERSIONS.latest(); | ||
const inaccessibleSpec = inaccessibleSpec_1.INACCESSIBLE_VERSIONS.latest(); | ||
const federationSpec = federationSpec_1.FEDERATION_VERSIONS.latest(); | ||
@@ -36,2 +34,3 @@ exports.FEDERATION_RESERVED_SUBGRAPH_NAME = '_'; | ||
const FEDERATION_VALIDATION_RULES = specifiedRules_1.specifiedSDLRules.filter(rule => !FEDERATION_OMITTED_VALIDATION_RULES.includes(rule)).concat(FEDERATION_SPECIFIC_VALIDATION_RULES); | ||
const ALL_DEFAULT_FEDERATION_DIRECTIVE_NAMES = Object.values(federationSpec_1.FederationDirectiveName); | ||
function validateFieldSetSelections({ directiveName, selectionSet, hasExternalInParents, metadata, onError, allowOnNonExternalLeafFields, allowFieldsWithArguments, }) { | ||
@@ -54,6 +53,6 @@ for (const selection of selectionSet.selections()) { | ||
onError(errorCode.err(`field "${field.coordinate}" should not be part of a @${directiveName} since it is already "effectively" provided by this subgraph ` | ||
+ `(while it is marked @${federationSpec_1.externalDirectiveSpec.name}, it is a @${federationSpec_1.keyDirectiveSpec.name} field of an extension type, which are not internally considered external for historical/backward compatibility reasons)`, { nodes: field.sourceAST })); | ||
+ `(while it is marked @${federationSpec_1.FederationDirectiveName.EXTERNAL}, it is a @${federationSpec_1.FederationDirectiveName.KEY} field of an extension type, which are not internally considered external for historical/backward compatibility reasons)`, { nodes: field.sourceAST })); | ||
} | ||
else { | ||
onError(errorCode.err(`field "${field.coordinate}" should not be part of a @${directiveName} since it is already provided by this subgraph (it is not marked @${federationSpec_1.externalDirectiveSpec.name})`, { nodes: field.sourceAST })); | ||
onError(errorCode.err(`field "${field.coordinate}" should not be part of a @${directiveName} since it is already provided by this subgraph (it is not marked @${federationSpec_1.FederationDirectiveName.EXTERNAL})`, { nodes: field.sourceAST })); | ||
} | ||
@@ -266,2 +265,28 @@ } | ||
} | ||
function validateShareableNotRepeatedOnSameDeclaration(element, metadata, errorCollector) { | ||
const shareableApplications = element.appliedDirectivesOf(metadata.shareableDirective()); | ||
if (shareableApplications.length <= 1) { | ||
return; | ||
} | ||
const byExtensions = shareableApplications.reduce((acc, v) => { | ||
const ext = v.ofExtension(); | ||
if (ext) { | ||
acc.with.add(ext, v); | ||
} | ||
else { | ||
acc.without.push(v); | ||
} | ||
return acc; | ||
}, { without: [], with: new utils_1.MultiMap() }); | ||
const groups = [byExtensions.without].concat((0, utils_1.mapValues)(byExtensions.with)); | ||
for (const group of groups) { | ||
if (group.length > 1) { | ||
const eltStr = element.kind === 'ObjectType' | ||
? `the same type declaration of "${element.coordinate}"` | ||
: `field "${element.coordinate}"`; | ||
errorCollector.push(error_1.ERRORS.INVALID_SHAREABLE_USAGE.err(`Invalid duplicate application of @shareable on ${eltStr}: ` | ||
+ '@shareable is only repeatable on types so it can be used simultaneously on a type definition and its extensions, but it should not be duplicated on the same definition/extension declaration', { nodes: (0, definitions_1.sourceASTs)(...group) })); | ||
} | ||
} | ||
} | ||
const printFieldCoordinate = (f) => `"${f.coordinate}"`; | ||
@@ -365,30 +390,30 @@ function formatFieldsToReturnType([type, implems]) { | ||
keyDirective() { | ||
return this.getFederationDirective(federationSpec_1.keyDirectiveSpec.name); | ||
return this.getFederationDirective(federationSpec_1.FederationDirectiveName.KEY); | ||
} | ||
overrideDirective() { | ||
return this.getFederationDirective(federationSpec_1.overrideDirectiveSpec.name); | ||
return this.getFederationDirective(federationSpec_1.FederationDirectiveName.OVERRIDE); | ||
} | ||
extendsDirective() { | ||
return this.getFederationDirective(federationSpec_1.extendsDirectiveSpec.name); | ||
return this.getFederationDirective(federationSpec_1.FederationDirectiveName.EXTENDS); | ||
} | ||
externalDirective() { | ||
return this.getFederationDirective(federationSpec_1.externalDirectiveSpec.name); | ||
return this.getFederationDirective(federationSpec_1.FederationDirectiveName.EXTERNAL); | ||
} | ||
requiresDirective() { | ||
return this.getFederationDirective(federationSpec_1.requiresDirectiveSpec.name); | ||
return this.getFederationDirective(federationSpec_1.FederationDirectiveName.REQUIRES); | ||
} | ||
providesDirective() { | ||
return this.getFederationDirective(federationSpec_1.providesDirectiveSpec.name); | ||
return this.getFederationDirective(federationSpec_1.FederationDirectiveName.PROVIDES); | ||
} | ||
shareableDirective() { | ||
return this.getFederationDirective(federationSpec_1.shareableDirectiveSpec.name); | ||
return this.getFederationDirective(federationSpec_1.FederationDirectiveName.SHAREABLE); | ||
} | ||
tagDirective() { | ||
return this.getFederationDirective(tagSpec.tagDirectiveSpec.name); | ||
return this.getFederationDirective(federationSpec_1.FederationDirectiveName.TAG); | ||
} | ||
composeDirective() { | ||
return this.getFederationDirective(federationSpec_1.composeDirectiveSpec.name); | ||
return this.getFederationDirective(federationSpec_1.FederationDirectiveName.COMPOSE_DIRECTIVE); | ||
} | ||
inaccessibleDirective() { | ||
return this.getFederationDirective(inaccessibleSpec.inaccessibleDirectiveSpec.name); | ||
return this.getFederationDirective(federationSpec_1.FederationDirectiveName.INACCESSIBLE); | ||
} | ||
@@ -418,3 +443,3 @@ allFederationDirectives() { | ||
fieldSetType() { | ||
return this.schema.type(this.federationTypeNameInSchema(federationSpec_1.fieldSetTypeSpec.name)); | ||
return this.schema.type(this.federationTypeNameInSchema(federationSpec_1.FederationTypeName.FIELD_SET)); | ||
} | ||
@@ -556,2 +581,14 @@ allFederationTypes() { | ||
} | ||
for (const objectType of schema.objectTypes()) { | ||
validateShareableNotRepeatedOnSameDeclaration(objectType, metadata, errorCollector); | ||
for (const field of objectType.fields()) { | ||
validateShareableNotRepeatedOnSameDeclaration(field, metadata, errorCollector); | ||
} | ||
} | ||
for (const shareableApplication of metadata.shareableDirective().applications()) { | ||
const element = shareableApplication.parent; | ||
if (element instanceof definitions_1.FieldDefinition && !(0, definitions_1.isObjectType)(element.parent)) { | ||
errorCollector.push(error_1.ERRORS.INVALID_SHAREABLE_USAGE.err(`Invalid use of @shareable on field "${element.coordinate}": only object type fields can be marked with @shareable`, { nodes: (0, definitions_1.sourceASTs)(shareableApplication, element.parent) })); | ||
} | ||
} | ||
return errorCollector; | ||
@@ -565,3 +602,3 @@ } | ||
(0, utils_1.assert)(metadata, `This method should only have been called on a subgraph schema`); | ||
if (federationSpec_1.ALL_FEDERATION_DIRECTIVES_DEFAULT_NAMES.includes(unknownDirectiveName)) { | ||
if (ALL_DEFAULT_FEDERATION_DIRECTIVE_NAMES.includes(unknownDirectiveName)) { | ||
if (metadata.isFed2Schema()) { | ||
@@ -583,3 +620,3 @@ const federationFeature = metadata.federationFeature(); | ||
else if (!metadata.isFed2Schema()) { | ||
const suggestions = (0, suggestions_1.suggestionList)(unknownDirectiveName, federationSpec_1.FEDERATION2_ONLY_SPEC_DIRECTIVES.map((spec) => spec.name)); | ||
const suggestions = (0, suggestions_1.suggestionList)(unknownDirectiveName, ALL_DEFAULT_FEDERATION_DIRECTIVE_NAMES); | ||
if (suggestions.length > 0) { | ||
@@ -629,3 +666,3 @@ return (0, error_1.withModifiedErrorMessage)(error, `${error.message}${(0, suggestions_1.didYouMean)(suggestions.map((s) => '@' + s))} If so, note that ${suggestions.length === 1 ? 'it is a federation 2 directive' : 'they are federation 2 directives'} but this schema is a federation 1 one. To be a federation 2 schema, it needs to @link to the federation specifcation v2.`); | ||
url: federationSpec.url.toString(), | ||
import: federationSpec_1.FEDERATION2_SPEC_DIRECTIVES.map((spec) => `@${spec.name}`), | ||
import: federationSpec.directiveSpecs().map((spec) => `@${spec.name}`), | ||
}); | ||
@@ -638,3 +675,3 @@ const errors = completeSubgraphSchema(schema); | ||
exports.setSchemaAsFed2Subgraph = setSchemaAsFed2Subgraph; | ||
exports.FEDERATION2_LINK_WTH_FULL_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.1", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective"])'; | ||
exports.FEDERATION2_LINK_WITH_FULL_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.2", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective"])'; | ||
function asFed2SubgraphDocument(document) { | ||
@@ -654,3 +691,3 @@ const fed2LinkExtension = { | ||
name: { kind: graphql_1.Kind.NAME, value: 'import' }, | ||
value: { kind: graphql_1.Kind.LIST, values: federationSpec_1.FEDERATION2_SPEC_DIRECTIVES.map((spec) => ({ kind: graphql_1.Kind.STRING, value: `@${spec.name}` })) } | ||
value: { kind: graphql_1.Kind.LIST, values: federationSpec.directiveSpecs().map((spec) => ({ kind: graphql_1.Kind.STRING, value: `@${spec.name}` })) } | ||
}] | ||
@@ -757,4 +794,4 @@ }] | ||
var _a, _b; | ||
for (const spec of [federationSpec_1.keyDirectiveSpec, federationSpec_1.providesDirectiveSpec, federationSpec_1.requiresDirectiveSpec]) { | ||
const directive = schema.directive(spec.name); | ||
for (const name of [federationSpec_1.FederationDirectiveName.KEY, federationSpec_1.FederationDirectiveName.PROVIDES, federationSpec_1.FederationDirectiveName.REQUIRES]) { | ||
const directive = schema.directive(name); | ||
if (!directive) { | ||
@@ -772,11 +809,5 @@ continue; | ||
} | ||
return [ | ||
federationSpec_1.fieldSetTypeSpec.checkOrAdd(schema, '_' + federationSpec_1.fieldSetTypeSpec.name), | ||
federationSpec_1.keyDirectiveSpec.checkOrAdd(schema), | ||
federationSpec_1.requiresDirectiveSpec.checkOrAdd(schema), | ||
federationSpec_1.providesDirectiveSpec.checkOrAdd(schema), | ||
federationSpec_1.extendsDirectiveSpec.checkOrAdd(schema), | ||
federationSpec_1.externalDirectiveSpec.checkOrAdd(schema), | ||
tagSpec.tagDirectiveSpec.checkOrAdd(schema), | ||
].flat(); | ||
return federationSpec_1.FEDERATION1_TYPES.map((spec) => spec.checkOrAdd(schema, '_' + spec.name)) | ||
.concat(federationSpec_1.FEDERATION1_DIRECTIVES.map((spec) => spec.checkOrAdd(schema))) | ||
.flat(); | ||
} | ||
@@ -820,3 +851,3 @@ function completeFed2SubgraphSchema(schema) { | ||
} | ||
if (directive.name === federationSpec_1.keyDirectiveSpec.name) { | ||
if (directive.name === federationSpec_1.FederationDirectiveName.KEY) { | ||
msg = msg + ' (the field should either be added to this subgraph or, if it should not be resolved by this subgraph, you need to add it to this subgraph with @external).'; | ||
@@ -1109,5 +1140,7 @@ } | ||
this.providedFields = new Set(); | ||
this.externalFieldsOnType = new Set(); | ||
this.externalDirective = this.metadata().externalDirective(); | ||
this.collectFakeExternals(); | ||
this.collectProvidedFields(); | ||
this.collectExternalsOnType(); | ||
} | ||
@@ -1147,4 +1180,13 @@ metadata() { | ||
} | ||
collectExternalsOnType() { | ||
for (const type of this.schema.objectTypes()) { | ||
if (type.hasAppliedDirective(this.externalDirective)) { | ||
for (const field of type.fields()) { | ||
this.externalFieldsOnType.add(field.coordinate); | ||
} | ||
} | ||
} | ||
} | ||
isExternal(field) { | ||
return field.hasAppliedDirective(this.externalDirective) && !this.isFakeExternal(field); | ||
return (field.hasAppliedDirective(this.externalDirective) || this.externalFieldsOnType.has(field.coordinate)) && !this.isFakeExternal(field); | ||
} | ||
@@ -1151,0 +1193,0 @@ isFakeExternal(field) { |
import { Schema } from "./definitions"; | ||
import { FeatureDefinition, FeatureDefinitions, FeatureVersion } from "./coreSpec"; | ||
import { DirectiveSpecification } from "./directiveAndTypeSpecification"; | ||
import { DirectiveSpecification, TypeSpecification } from "./directiveAndTypeSpecification"; | ||
import { GraphQLError } from "graphql"; | ||
export declare const federationIdentity = "https://specs.apollo.dev/federation"; | ||
export declare const fieldSetTypeSpec: import("./directiveAndTypeSpecification").TypeSpecification; | ||
export declare const keyDirectiveSpec: DirectiveSpecification; | ||
export declare const extendsDirectiveSpec: DirectiveSpecification; | ||
export declare const externalDirectiveSpec: DirectiveSpecification; | ||
export declare const requiresDirectiveSpec: DirectiveSpecification; | ||
export declare const providesDirectiveSpec: DirectiveSpecification; | ||
export declare const shareableDirectiveSpec: DirectiveSpecification; | ||
export declare const overrideDirectiveSpec: DirectiveSpecification; | ||
export declare const composeDirectiveSpec: DirectiveSpecification; | ||
export declare const FEDERATION2_ONLY_SPEC_DIRECTIVES: DirectiveSpecification[]; | ||
export declare const FEDERATION2_1_ONLY_SPEC_DIRECTIVES: DirectiveSpecification[]; | ||
export declare const FEDERATION2_SPEC_DIRECTIVES: DirectiveSpecification[]; | ||
export declare const ALL_FEDERATION_DIRECTIVES_DEFAULT_NAMES: string[]; | ||
export declare const FEDERATION_SPEC_TYPES: import("./directiveAndTypeSpecification").TypeSpecification[]; | ||
export declare enum FederationTypeName { | ||
FIELD_SET = "FieldSet" | ||
} | ||
export declare enum FederationDirectiveName { | ||
KEY = "key", | ||
EXTERNAL = "external", | ||
REQUIRES = "requires", | ||
PROVIDES = "provides", | ||
EXTENDS = "extends", | ||
SHAREABLE = "shareable", | ||
OVERRIDE = "override", | ||
TAG = "tag", | ||
INACCESSIBLE = "inaccessible", | ||
COMPOSE_DIRECTIVE = "composeDirective" | ||
} | ||
export declare const FEDERATION1_TYPES: TypeSpecification[]; | ||
export declare const FEDERATION1_DIRECTIVES: DirectiveSpecification[]; | ||
export declare class FederationSpecDefinition extends FeatureDefinition { | ||
private readonly _directiveSpecs; | ||
private readonly _typeSpecs; | ||
constructor(version: FeatureVersion); | ||
private allFedDirectives; | ||
private registerDirective; | ||
private registerType; | ||
directiveSpecs(): readonly DirectiveSpecification[]; | ||
typeSpecs(): readonly TypeSpecification[]; | ||
addElementsToSchema(schema: Schema): GraphQLError[]; | ||
@@ -24,0 +32,0 @@ allElementNames(): string[]; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.FEDERATION_VERSIONS = exports.FederationSpecDefinition = exports.FEDERATION_SPEC_TYPES = exports.ALL_FEDERATION_DIRECTIVES_DEFAULT_NAMES = exports.FEDERATION2_SPEC_DIRECTIVES = exports.FEDERATION2_1_ONLY_SPEC_DIRECTIVES = exports.FEDERATION2_ONLY_SPEC_DIRECTIVES = exports.composeDirectiveSpec = exports.overrideDirectiveSpec = exports.shareableDirectiveSpec = exports.providesDirectiveSpec = exports.requiresDirectiveSpec = exports.externalDirectiveSpec = exports.extendsDirectiveSpec = exports.keyDirectiveSpec = exports.fieldSetTypeSpec = exports.federationIdentity = void 0; | ||
exports.FEDERATION_VERSIONS = exports.FederationSpecDefinition = exports.FEDERATION1_DIRECTIVES = exports.FEDERATION1_TYPES = exports.FederationDirectiveName = exports.FederationTypeName = exports.federationIdentity = void 0; | ||
const definitions_1 = require("./definitions"); | ||
@@ -14,5 +14,22 @@ const coreSpec_1 = require("./coreSpec"); | ||
exports.federationIdentity = 'https://specs.apollo.dev/federation'; | ||
exports.fieldSetTypeSpec = (0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name: 'FieldSet' }); | ||
exports.keyDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: 'key', | ||
var FederationTypeName; | ||
(function (FederationTypeName) { | ||
FederationTypeName["FIELD_SET"] = "FieldSet"; | ||
})(FederationTypeName = exports.FederationTypeName || (exports.FederationTypeName = {})); | ||
var FederationDirectiveName; | ||
(function (FederationDirectiveName) { | ||
FederationDirectiveName["KEY"] = "key"; | ||
FederationDirectiveName["EXTERNAL"] = "external"; | ||
FederationDirectiveName["REQUIRES"] = "requires"; | ||
FederationDirectiveName["PROVIDES"] = "provides"; | ||
FederationDirectiveName["EXTENDS"] = "extends"; | ||
FederationDirectiveName["SHAREABLE"] = "shareable"; | ||
FederationDirectiveName["OVERRIDE"] = "override"; | ||
FederationDirectiveName["TAG"] = "tag"; | ||
FederationDirectiveName["INACCESSIBLE"] = "inaccessible"; | ||
FederationDirectiveName["COMPOSE_DIRECTIVE"] = "composeDirective"; | ||
})(FederationDirectiveName = exports.FederationDirectiveName || (exports.FederationDirectiveName = {})); | ||
const fieldSetTypeSpec = (0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name: FederationTypeName.FIELD_SET }); | ||
const keyDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: FederationDirectiveName.KEY, | ||
locations: [graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.INTERFACE], | ||
@@ -28,8 +45,8 @@ repeatable: true, | ||
}); | ||
exports.extendsDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: 'extends', | ||
const extendsDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: FederationDirectiveName.EXTENDS, | ||
locations: [graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.INTERFACE], | ||
}); | ||
exports.externalDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: 'external', | ||
const externalDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: FederationDirectiveName.EXTERNAL, | ||
locations: [graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.FIELD_DEFINITION], | ||
@@ -41,4 +58,4 @@ argumentFct: (schema) => ({ | ||
}); | ||
exports.requiresDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: 'requires', | ||
const requiresDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: FederationDirectiveName.REQUIRES, | ||
locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION], | ||
@@ -50,4 +67,4 @@ argumentFct: (schema) => ({ | ||
}); | ||
exports.providesDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: 'provides', | ||
const providesDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: FederationDirectiveName.PROVIDES, | ||
locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION], | ||
@@ -59,23 +76,15 @@ argumentFct: (schema) => ({ | ||
}); | ||
exports.shareableDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: 'shareable', | ||
locations: [graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.FIELD_DEFINITION], | ||
}); | ||
exports.overrideDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: 'override', | ||
locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION], | ||
argumentFct: (schema) => ({ | ||
args: [{ name: 'from', type: new definitions_1.NonNullType(schema.stringType()) }], | ||
errors: [], | ||
}), | ||
}); | ||
exports.composeDirectiveSpec = (0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: 'composeDirective', | ||
locations: [graphql_1.DirectiveLocation.SCHEMA], | ||
repeatable: true, | ||
argumentFct: (schema) => ({ | ||
args: [{ name: 'name', type: schema.stringType() }], | ||
errors: [], | ||
}), | ||
}); | ||
const legacyFederationTypes = [ | ||
fieldSetTypeSpec, | ||
]; | ||
const legacyFederationDirectives = [ | ||
keyDirectiveSpec, | ||
requiresDirectiveSpec, | ||
providesDirectiveSpec, | ||
externalDirectiveSpec, | ||
tagSpec_1.TAG_VERSIONS.latest().tagDirectiveSpec, | ||
extendsDirectiveSpec, | ||
]; | ||
exports.FEDERATION1_TYPES = legacyFederationTypes; | ||
exports.FEDERATION1_DIRECTIVES = legacyFederationDirectives; | ||
function fieldsArgument(schema) { | ||
@@ -89,36 +98,51 @@ return { name: 'fields', type: fieldSetType(schema) }; | ||
} | ||
exports.FEDERATION2_ONLY_SPEC_DIRECTIVES = [ | ||
exports.shareableDirectiveSpec, | ||
inaccessibleSpec_1.INACCESSIBLE_VERSIONS.latest().inaccessibleDirectiveSpec, | ||
exports.overrideDirectiveSpec, | ||
]; | ||
exports.FEDERATION2_1_ONLY_SPEC_DIRECTIVES = [ | ||
exports.composeDirectiveSpec, | ||
]; | ||
const PRE_FEDERATION2_SPEC_DIRECTIVES = [ | ||
exports.keyDirectiveSpec, | ||
exports.requiresDirectiveSpec, | ||
exports.providesDirectiveSpec, | ||
exports.externalDirectiveSpec, | ||
tagSpec_1.TAG_VERSIONS.latest().tagDirectiveSpec, | ||
exports.extendsDirectiveSpec, | ||
]; | ||
exports.FEDERATION2_SPEC_DIRECTIVES = [ | ||
...PRE_FEDERATION2_SPEC_DIRECTIVES, | ||
...exports.FEDERATION2_ONLY_SPEC_DIRECTIVES, | ||
...exports.FEDERATION2_1_ONLY_SPEC_DIRECTIVES, | ||
]; | ||
exports.ALL_FEDERATION_DIRECTIVES_DEFAULT_NAMES = exports.FEDERATION2_SPEC_DIRECTIVES.map((spec) => spec.name); | ||
exports.FEDERATION_SPEC_TYPES = [ | ||
exports.fieldSetTypeSpec, | ||
]; | ||
class FederationSpecDefinition extends coreSpec_1.FeatureDefinition { | ||
constructor(version) { | ||
super(new coreSpec_1.FeatureUrl(exports.federationIdentity, 'federation', version)); | ||
this._directiveSpecs = new utils_1.MapWithCachedArrays(); | ||
this._typeSpecs = new utils_1.MapWithCachedArrays(); | ||
for (const type of legacyFederationTypes) { | ||
this.registerType(type); | ||
} | ||
for (const directive of legacyFederationDirectives) { | ||
this.registerDirective(directive); | ||
} | ||
this.registerDirective((0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: FederationDirectiveName.SHAREABLE, | ||
locations: [graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.FIELD_DEFINITION], | ||
repeatable: version >= (new coreSpec_1.FeatureVersion(2, 2)), | ||
})); | ||
this.registerDirective(inaccessibleSpec_1.INACCESSIBLE_VERSIONS.latest().inaccessibleDirectiveSpec); | ||
this.registerDirective((0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: FederationDirectiveName.OVERRIDE, | ||
locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION], | ||
argumentFct: (schema) => ({ | ||
args: [{ name: 'from', type: new definitions_1.NonNullType(schema.stringType()) }], | ||
errors: [], | ||
}), | ||
})); | ||
if (version >= (new coreSpec_1.FeatureVersion(2, 1))) { | ||
this.registerDirective((0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
name: FederationDirectiveName.COMPOSE_DIRECTIVE, | ||
locations: [graphql_1.DirectiveLocation.SCHEMA], | ||
repeatable: true, | ||
argumentFct: (schema) => ({ | ||
args: [{ name: 'name', type: schema.stringType() }], | ||
errors: [], | ||
}), | ||
})); | ||
} | ||
} | ||
allFedDirectives() { | ||
return PRE_FEDERATION2_SPEC_DIRECTIVES | ||
.concat(exports.FEDERATION2_ONLY_SPEC_DIRECTIVES) | ||
.concat(this.url.version >= (new coreSpec_1.FeatureVersion(2, 1)) ? exports.FEDERATION2_1_ONLY_SPEC_DIRECTIVES : []); | ||
registerDirective(spec) { | ||
this._directiveSpecs.set(spec.name, spec); | ||
} | ||
registerType(spec) { | ||
this._typeSpecs.set(spec.name, spec); | ||
} | ||
directiveSpecs() { | ||
return this._directiveSpecs.values(); | ||
} | ||
typeSpecs() { | ||
return this._typeSpecs.values(); | ||
} | ||
addElementsToSchema(schema) { | ||
@@ -128,4 +152,6 @@ const feature = this.featureInSchema(schema); | ||
let errors = []; | ||
errors = errors.concat(this.addTypeSpec(schema, exports.fieldSetTypeSpec)); | ||
for (const directive of this.allFedDirectives()) { | ||
for (const type of this.typeSpecs()) { | ||
errors = errors.concat(this.addTypeSpec(schema, type)); | ||
} | ||
for (const directive of this.directiveSpecs()) { | ||
errors = errors.concat(this.addDirectiveSpec(schema, directive)); | ||
@@ -136,5 +162,4 @@ } | ||
allElementNames() { | ||
return this.allFedDirectives().map((spec) => `@${spec.name}`).concat([ | ||
exports.fieldSetTypeSpec.name, | ||
]); | ||
return this.directiveSpecs().map((spec) => `@${spec.name}`) | ||
.concat(this.typeSpecs().map((spec) => spec.name)); | ||
} | ||
@@ -145,4 +170,5 @@ } | ||
.add(new FederationSpecDefinition(new coreSpec_1.FeatureVersion(2, 0))) | ||
.add(new FederationSpecDefinition(new coreSpec_1.FeatureVersion(2, 1))); | ||
.add(new FederationSpecDefinition(new coreSpec_1.FeatureVersion(2, 1))) | ||
.add(new FederationSpecDefinition(new coreSpec_1.FeatureVersion(2, 2))); | ||
(0, knownCoreFeatures_1.registerKnownFeature)(exports.FEDERATION_VERSIONS); | ||
//# sourceMappingURL=federationSpec.js.map |
import { Schema } from "./definitions"; | ||
export declare const introspectionFieldNames: string[]; | ||
export declare const introspectionTypeNames: string[]; | ||
export declare function isIntrospectionName(name: string): boolean; | ||
export declare function addIntrospectionFields(schema: Schema): void; | ||
//# sourceMappingURL=introspection.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.addIntrospectionFields = exports.isIntrospectionName = exports.introspectionFieldNames = void 0; | ||
exports.addIntrospectionFields = exports.isIntrospectionName = exports.introspectionTypeNames = exports.introspectionFieldNames = void 0; | ||
const graphql_1 = require("graphql"); | ||
const definitions_1 = require("./definitions"); | ||
exports.introspectionFieldNames = ['__schema', '__type']; | ||
exports.introspectionTypeNames = [ | ||
'__Schema', | ||
'__Directive', | ||
'__DirectiveLocation', | ||
'__Type', | ||
'__Field', | ||
'__InputValue', | ||
'__EnumValue', | ||
'__TypeKind', | ||
]; | ||
function isIntrospectionName(name) { | ||
@@ -8,0 +18,0 @@ return name.startsWith('__'); |
@@ -93,2 +93,3 @@ import { DocumentNode, FieldNode, FragmentDefinitionNode, SelectionNode, SelectionSetNode } from "graphql"; | ||
canApplyAtType(type: CompositeType): boolean; | ||
private validForSchema; | ||
toString(indent?: string): string; | ||
@@ -95,0 +96,0 @@ } |
@@ -17,3 +17,3 @@ import { GraphQLError } from "graphql"; | ||
export declare type UpgradeChangeID = UpgradeChange['id']; | ||
export declare type UpgradeChange = ExternalOnTypeExtensionRemoval | TypeExtensionRemoval | UnusedExternalRemoval | TypeWithOnlyUnusedExternalRemoval | ExternalOnInterfaceRemoval | InactiveProvidesOrRequiresRemoval | InactiveProvidesOrRequiresFieldsRemoval | ShareableFieldAddition | ShareableTypeAddition | KeyOnInterfaceRemoval | ProvidesOrRequiresOnInterfaceFieldRemoval | ProvidesOnNonCompositeRemoval | FieldsArgumentCoercionToString | RemovedTagOnExternal; | ||
export declare type UpgradeChange = ExternalOnTypeExtensionRemoval | TypeExtensionRemoval | UnusedExternalRemoval | TypeWithOnlyUnusedExternalRemoval | ExternalOnInterfaceRemoval | ExternalOnObjectTypeRemoval | InactiveProvidesOrRequiresRemoval | InactiveProvidesOrRequiresFieldsRemoval | ShareableFieldAddition | ShareableTypeAddition | KeyOnInterfaceRemoval | ProvidesOrRequiresOnInterfaceFieldRemoval | ProvidesOnNonCompositeRemoval | FieldsArgumentCoercionToString | RemovedTagOnExternal; | ||
export declare class ExternalOnTypeExtensionRemoval { | ||
@@ -37,2 +37,8 @@ readonly field: string; | ||
} | ||
export declare class ExternalOnObjectTypeRemoval { | ||
readonly type: string; | ||
readonly id: "EXTERNAL_ON_OBJECT_TYPE_REMOVAL"; | ||
constructor(type: string); | ||
toString(): string; | ||
} | ||
export declare class UnusedExternalRemoval { | ||
@@ -39,0 +45,0 @@ readonly field: string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.upgradeSubgraphsIfNecessary = exports.RemovedTagOnExternal = exports.FieldsArgumentCoercionToString = exports.ProvidesOnNonCompositeRemoval = exports.ProvidesOrRequiresOnInterfaceFieldRemoval = exports.KeyOnInterfaceRemoval = exports.ShareableTypeAddition = exports.ShareableFieldAddition = exports.InactiveProvidesOrRequiresFieldsRemoval = exports.InactiveProvidesOrRequiresRemoval = exports.TypeWithOnlyUnusedExternalRemoval = exports.UnusedExternalRemoval = exports.ExternalOnInterfaceRemoval = exports.TypeExtensionRemoval = exports.ExternalOnTypeExtensionRemoval = void 0; | ||
exports.upgradeSubgraphsIfNecessary = exports.RemovedTagOnExternal = exports.FieldsArgumentCoercionToString = exports.ProvidesOnNonCompositeRemoval = exports.ProvidesOrRequiresOnInterfaceFieldRemoval = exports.KeyOnInterfaceRemoval = exports.ShareableTypeAddition = exports.ShareableFieldAddition = exports.InactiveProvidesOrRequiresFieldsRemoval = exports.InactiveProvidesOrRequiresRemoval = exports.TypeWithOnlyUnusedExternalRemoval = exports.UnusedExternalRemoval = exports.ExternalOnObjectTypeRemoval = exports.ExternalOnInterfaceRemoval = exports.TypeExtensionRemoval = exports.ExternalOnTypeExtensionRemoval = void 0; | ||
const graphql_1 = require("graphql"); | ||
@@ -9,4 +9,4 @@ const error_1 = require("./error"); | ||
const utils_1 = require("./utils"); | ||
const values_1 = require("./values"); | ||
const federationSpec_1 = require("./federationSpec"); | ||
const values_1 = require("./values"); | ||
class ExternalOnTypeExtensionRemoval { | ||
@@ -42,2 +42,12 @@ constructor(field) { | ||
exports.ExternalOnInterfaceRemoval = ExternalOnInterfaceRemoval; | ||
class ExternalOnObjectTypeRemoval { | ||
constructor(type) { | ||
this.type = type; | ||
this.id = 'EXTERNAL_ON_OBJECT_TYPE_REMOVAL'; | ||
} | ||
toString() { | ||
return `Removed @external directive on object type "${this.type}": @external on types was not rejected but was inactive in fed1`; | ||
} | ||
} | ||
exports.ExternalOnObjectTypeRemoval = ExternalOnObjectTypeRemoval; | ||
class UnusedExternalRemoval { | ||
@@ -245,3 +255,3 @@ constructor(field) { | ||
renameFederationTypes() { | ||
for (const typeSpec of federationSpec_1.FEDERATION_SPEC_TYPES) { | ||
for (const typeSpec of federationSpec_1.FEDERATION1_TYPES) { | ||
const typeNameInOriginal = this.originalSubgraph.metadata().federationTypeNameInSchema(typeSpec.name); | ||
@@ -284,2 +294,3 @@ const type = this.schema.type(typeNameInOriginal); | ||
this.removeExternalOnInterface(); | ||
this.removeExternalOnObjectTypes(); | ||
this.removeExternalOnTypeExtensions(); | ||
@@ -356,2 +367,11 @@ this.fixInactiveProvidesAndRequires(); | ||
} | ||
removeExternalOnObjectTypes() { | ||
for (const type of this.schema.objectTypes()) { | ||
const external = type.appliedDirectivesOf(this.metadata.externalDirective())[0]; | ||
if (external) { | ||
this.addChange(new ExternalOnObjectTypeRemoval(type.coordinate)); | ||
external.remove(); | ||
} | ||
} | ||
} | ||
replaceFederationDirectiveApplication(application, before, fields, updatedSourceAST) { | ||
@@ -358,0 +378,0 @@ const directive = application.definition; |
@@ -27,2 +27,3 @@ export declare function assert(condition: any, message: string | (() => string)): asserts condition; | ||
export declare function arrayEquals<T>(a: readonly T[], b: readonly T[], equalFct?: (e1: T, e2: T) => boolean): boolean; | ||
export declare function isSubset<T>(superset: Set<T>, maybeSubset: Set<T>): boolean; | ||
export declare function firstOf<T>(iterable: Iterable<T>): T | undefined; | ||
@@ -29,0 +30,0 @@ export declare function mapValues<V>(map: ReadonlyMap<any, V>): V[]; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.removeArrayElement = exports.isDefined = exports.printHumanReadableList = exports.joinStrings = exports.validateStringContainsBoolean = exports.copyWitNewLength = exports.MapWithCachedArrays = exports.setValues = exports.mapEntries = exports.mapKeys = exports.mapValues = exports.firstOf = exports.arrayEquals = exports.OrderedMap = exports.SetMultiMap = exports.MultiMap = exports.assertUnreachable = exports.assert = void 0; | ||
exports.removeArrayElement = exports.isDefined = exports.printHumanReadableList = exports.joinStrings = exports.validateStringContainsBoolean = exports.copyWitNewLength = exports.MapWithCachedArrays = exports.setValues = exports.mapEntries = exports.mapKeys = exports.mapValues = exports.firstOf = exports.isSubset = exports.arrayEquals = exports.OrderedMap = exports.SetMultiMap = exports.MultiMap = exports.assertUnreachable = exports.assert = void 0; | ||
function assert(condition, message) { | ||
@@ -134,2 +134,14 @@ if (!condition) { | ||
exports.arrayEquals = arrayEquals; | ||
function isSubset(superset, maybeSubset) { | ||
if (superset === maybeSubset) { | ||
return true; | ||
} | ||
for (const elt of maybeSubset) { | ||
if (!superset.has(elt)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
exports.isSubset = isSubset; | ||
function firstOf(iterable) { | ||
@@ -136,0 +148,0 @@ const res = iterable[Symbol.iterator]().next(); |
@@ -55,3 +55,5 @@ "use strict"; | ||
for (const type of this.schema.types()) { | ||
this.validateName(type); | ||
if (!introspection_1.introspectionTypeNames.includes(type.name)) { | ||
this.validateName(type); | ||
} | ||
switch (type.kind) { | ||
@@ -110,2 +112,3 @@ case 'ObjectType': | ||
if ((0, introspection_1.isIntrospectionName)(elt.name)) { | ||
this.addError(`Name "${elt.name}" must not begin with "__", which is reserved by GraphQL introspection.`, elt.sourceAST ? { nodes: elt.sourceAST } : {}); | ||
return; | ||
@@ -112,0 +115,0 @@ } |
{ | ||
"name": "@apollo/federation-internals", | ||
"version": "2.1.4", | ||
"version": "2.2.0", | ||
"description": "Apollo Federation internal utilities", | ||
@@ -23,3 +23,3 @@ "main": "dist/index.js", | ||
"engines": { | ||
"node": ">=12.13.0" | ||
"node": ">=14.15.0" | ||
}, | ||
@@ -36,3 +36,3 @@ "dependencies": { | ||
}, | ||
"gitHead": "413ef7911df24c26a1150157e42539f6d4b710df" | ||
"gitHead": "4c48e89fa215a24aacb02d68f83d2cbc7b0f5193" | ||
} |
@@ -1,2 +0,2 @@ | ||
import { buildSupergraphSchema, extractSubgraphsFromSupergraph } from ".."; | ||
import { buildSupergraphSchema, extractSubgraphsFromSupergraph, InputObjectType } from ".."; | ||
@@ -537,2 +537,65 @@ | ||
test('preserves default values of input object fields', () => { | ||
const supergraph = ` | ||
schema | ||
@link(url: "https://specs.apollo.dev/link/v1.0") | ||
@link(url: "https://specs.apollo.dev/join/v0.2", for: EXECUTION) | ||
{ | ||
query: Query | ||
} | ||
directive @join__field(graph: join__Graph!, requires: join__FieldSet, provides: join__FieldSet, type: String, external: Boolean, override: String, usedOverridden: Boolean) repeatable on FIELD_DEFINITION | INPUT_FIELD_DEFINITION | ||
directive @join__graph(name: String!, url: String!) on ENUM_VALUE | ||
directive @join__implements(graph: join__Graph!, interface: String!) repeatable on OBJECT | INTERFACE | ||
directive @join__type(graph: join__Graph!, key: join__FieldSet, extension: Boolean! = false, resolvable: Boolean! = true) repeatable on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT | SCALAR | ||
directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA | ||
input Input | ||
@join__type(graph: SERVICE) | ||
{ | ||
a: Int! = 1234 | ||
} | ||
scalar join__FieldSet | ||
enum join__Graph { | ||
SERVICE @join__graph(name: "service", url: "") | ||
} | ||
scalar link__Import | ||
enum link__Purpose { | ||
""" | ||
\`SECURITY\` features provide metadata necessary to securely resolve fields. | ||
""" | ||
SECURITY | ||
""" | ||
\`EXECUTION\` features provide metadata necessary for operation execution. | ||
""" | ||
EXECUTION | ||
} | ||
type Query | ||
@join__type(graph: SERVICE) | ||
{ | ||
field(input: Input!): String | ||
} | ||
`; | ||
const schema = buildSupergraphSchema(supergraph)[0]; | ||
const subgraphs = extractSubgraphsFromSupergraph(schema); | ||
const subgraph = subgraphs.get('service') | ||
const inputType = subgraph?.schema.type('Input') as InputObjectType | undefined | ||
const inputFieldA = inputType?.field('a') | ||
expect(inputFieldA?.defaultValue).toBe(1234) | ||
}) | ||
test('throw meaningful error for invalid federation directive fieldSet', () => { | ||
@@ -539,0 +602,0 @@ const supergraph = ` |
@@ -1,2 +0,2 @@ | ||
import { FEDERATION2_LINK_WTH_FULL_IMPORTS } from '..'; | ||
import { FEDERATION2_LINK_WITH_FULL_IMPORTS } from '..'; | ||
import { ObjectType } from '../definitions'; | ||
@@ -95,3 +95,3 @@ import { buildSubgraph, Subgraphs } from '../federation'; | ||
schema | ||
${FEDERATION2_LINK_WTH_FULL_IMPORTS} | ||
${FEDERATION2_LINK_WITH_FULL_IMPORTS} | ||
{ | ||
@@ -152,3 +152,3 @@ query: Query | ||
schema | ||
${FEDERATION2_LINK_WTH_FULL_IMPORTS} | ||
${FEDERATION2_LINK_WITH_FULL_IMPORTS} | ||
{ | ||
@@ -155,0 +155,0 @@ query: Query |
@@ -671,3 +671,3 @@ import { DocumentNode } from 'graphql'; | ||
directive @federation__shareable on OBJECT | FIELD_DEFINITION | ||
directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION | ||
@@ -1130,1 +1130,60 @@ directive @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ||
}) | ||
describe('@shareable', () => { | ||
it('can only be applied to fields of object types', () => { | ||
const doc = gql` | ||
interface I { | ||
a: Int @shareable | ||
} | ||
`; | ||
expect(buildForErrors(doc)).toStrictEqual([[ | ||
'INVALID_SHAREABLE_USAGE', | ||
'[S] Invalid use of @shareable on field "I.a": only object type fields can be marked with @shareable' | ||
]]); | ||
}); | ||
it('rejects duplicate @shareable on the same definition declaration', () => { | ||
const doc = gql` | ||
type E @shareable @key(fields: "id") @shareable { | ||
id: ID! | ||
a: Int | ||
} | ||
`; | ||
expect(buildForErrors(doc)).toStrictEqual([[ | ||
'INVALID_SHAREABLE_USAGE', | ||
'[S] Invalid duplicate application of @shareable on the same type declaration of "E": @shareable is only repeatable on types so it can be used simultaneously on a type definition and its extensions, but it should not be duplicated on the same definition/extension declaration' | ||
]]); | ||
}); | ||
it('rejects duplicate @shareable on the same extension declaration', () => { | ||
const doc = gql` | ||
type E @shareable { | ||
id: ID! | ||
a: Int | ||
} | ||
extend type E @shareable @shareable { | ||
b: Int | ||
} | ||
`; | ||
expect(buildForErrors(doc)).toStrictEqual([[ | ||
'INVALID_SHAREABLE_USAGE', | ||
'[S] Invalid duplicate application of @shareable on the same type declaration of "E": @shareable is only repeatable on types so it can be used simultaneously on a type definition and its extensions, but it should not be duplicated on the same definition/extension declaration' | ||
]]); | ||
}); | ||
it('rejects duplicate @shareable on a field', () => { | ||
const doc = gql` | ||
type E { | ||
a: Int @shareable @shareable | ||
} | ||
`; | ||
expect(buildForErrors(doc)).toStrictEqual([[ | ||
'INVALID_SHAREABLE_USAGE', | ||
'[S] Invalid duplicate application of @shareable on field "E.a": @shareable is only repeatable on types so it can be used simultaneously on a type definition and its extensions, but it should not be duplicated on the same definition/extension declaration' | ||
]]); | ||
}); | ||
}); |
@@ -58,2 +58,3 @@ import { | ||
import { ERRORS, errorCauses, withModifiedErrorNodes } from "./error"; | ||
import { introspectionTypeNames } from "./introspection"; | ||
@@ -214,2 +215,6 @@ function buildValue(value?: ValueNode): any { | ||
case 'InputObjectTypeDefinition': | ||
// Like graphql-js, we just silently ignore definitions for introspection types | ||
if (introspectionTypeNames.includes(definitionNode.name.value)) { | ||
continue; | ||
} | ||
typeDefinitions.push(definitionNode); | ||
@@ -245,2 +250,6 @@ let type = schema.type(definitionNode.name.value); | ||
case 'InputObjectTypeExtension': | ||
// Like graphql-js, we just silently ignore definitions for introspection types | ||
if (introspectionTypeNames.includes(definitionNode.name.value)) { | ||
continue; | ||
} | ||
typeExtensions.push(definitionNode); | ||
@@ -247,0 +256,0 @@ const existing = schema.type(definitionNode.name.value); |
@@ -408,2 +408,8 @@ import { ASTNode, GraphQLError, GraphQLErrorOptions, GraphQLFormattedError } from "graphql"; | ||
const INVALID_SHAREABLE_USAGE = makeCodeDefinition( | ||
'INVALID_SHAREABLE_USAGE', | ||
'The `@shareable` federation directive is used in an invalid way.', | ||
{ addedIn: '2.1.2' }, | ||
); | ||
const INVALID_LINK_DIRECTIVE_USAGE = makeCodeDefinition( | ||
@@ -585,2 +591,3 @@ 'INVALID_LINK_DIRECTIVE_USAGE', | ||
INVALID_FIELD_SHARING, | ||
INVALID_SHAREABLE_USAGE, | ||
INVALID_LINK_DIRECTIVE_USAGE, | ||
@@ -587,0 +594,0 @@ INVALID_LINK_IDENTIFIER, |
@@ -332,5 +332,9 @@ import { | ||
const fieldBaseType = baseType(field.type!); | ||
const isShareable = isObjectType(type) && subgraphs.values().filter((s) => s.schema.type(type.name)).length > 1; | ||
for (const subgraph of subgraphs) { | ||
if (subgraph.schema.type(fieldBaseType.name)) { | ||
addSubgraphField(field, subgraph); | ||
const subgraphField = addSubgraphField(field, subgraph); | ||
if (subgraphField && isShareable) { | ||
subgraphField.applyDirective(subgraph.metadata().shareableDirective()); | ||
} | ||
} | ||
@@ -345,2 +349,8 @@ } | ||
} else { | ||
const isShareable = isObjectType(type) | ||
&& (fieldApplications as Directive<any, { external?: boolean, usedOverridden?: boolean }>[]).filter((application) => { | ||
const args = application.arguments(); | ||
return !args.external && !args.usedOverridden; | ||
}).length > 1; | ||
for (const application of fieldApplications) { | ||
@@ -373,2 +383,5 @@ const args = application.arguments(); | ||
} | ||
if (isShareable && !args.external && !args.usedOverridden) { | ||
subgraphField.applyDirective(subgraph.metadata().shareableDirective()); | ||
} | ||
} | ||
@@ -601,3 +614,5 @@ } | ||
: copyType(supergraphField.type!, subgraph.schema, subgraph.name); | ||
return (subgraphType as InputObjectType).addField(supergraphField.name, copiedType); | ||
const field = (subgraphType as InputObjectType).addField(supergraphField.name, copiedType); | ||
field.defaultValue = supergraphField.defaultValue | ||
return field | ||
} else { | ||
@@ -604,0 +619,0 @@ return undefined; |
@@ -12,5 +12,6 @@ import { | ||
DirectiveSpecification, | ||
TypeSpecification, | ||
} from "./directiveAndTypeSpecification"; | ||
import { DirectiveLocation, GraphQLError } from "graphql"; | ||
import { assert } from "./utils"; | ||
import { assert, MapWithCachedArrays } from "./utils"; | ||
import { TAG_VERSIONS } from "./tagSpec"; | ||
@@ -23,6 +24,23 @@ import { federationMetadata } from "./federation"; | ||
export const fieldSetTypeSpec = createScalarTypeSpecification({ name: 'FieldSet' }); | ||
export enum FederationTypeName { | ||
FIELD_SET = 'FieldSet', | ||
} | ||
export const keyDirectiveSpec = createDirectiveSpecification({ | ||
name:'key', | ||
export enum FederationDirectiveName { | ||
KEY = 'key', | ||
EXTERNAL = 'external', | ||
REQUIRES = 'requires', | ||
PROVIDES = 'provides', | ||
EXTENDS = 'extends', | ||
SHAREABLE = 'shareable', | ||
OVERRIDE = 'override', | ||
TAG = 'tag', | ||
INACCESSIBLE = 'inaccessible', | ||
COMPOSE_DIRECTIVE = 'composeDirective', | ||
} | ||
const fieldSetTypeSpec = createScalarTypeSpecification({ name: FederationTypeName.FIELD_SET }); | ||
const keyDirectiveSpec = createDirectiveSpecification({ | ||
name: FederationDirectiveName.KEY, | ||
locations: [DirectiveLocation.OBJECT, DirectiveLocation.INTERFACE], | ||
@@ -39,9 +57,9 @@ repeatable: true, | ||
export const extendsDirectiveSpec = createDirectiveSpecification({ | ||
name:'extends', | ||
const extendsDirectiveSpec = createDirectiveSpecification({ | ||
name: FederationDirectiveName.EXTENDS, | ||
locations: [DirectiveLocation.OBJECT, DirectiveLocation.INTERFACE], | ||
}); | ||
export const externalDirectiveSpec = createDirectiveSpecification({ | ||
name:'external', | ||
const externalDirectiveSpec = createDirectiveSpecification({ | ||
name: FederationDirectiveName.EXTERNAL, | ||
locations: [DirectiveLocation.OBJECT, DirectiveLocation.FIELD_DEFINITION], | ||
@@ -54,4 +72,4 @@ argumentFct: (schema) => ({ | ||
export const requiresDirectiveSpec = createDirectiveSpecification({ | ||
name:'requires', | ||
const requiresDirectiveSpec = createDirectiveSpecification({ | ||
name: FederationDirectiveName.REQUIRES, | ||
locations: [DirectiveLocation.FIELD_DEFINITION], | ||
@@ -64,4 +82,4 @@ argumentFct: (schema) => ({ | ||
export const providesDirectiveSpec = createDirectiveSpecification({ | ||
name:'provides', | ||
const providesDirectiveSpec = createDirectiveSpecification({ | ||
name: FederationDirectiveName.PROVIDES, | ||
locations: [DirectiveLocation.FIELD_DEFINITION], | ||
@@ -74,25 +92,17 @@ argumentFct: (schema) => ({ | ||
export const shareableDirectiveSpec = createDirectiveSpecification({ | ||
name: 'shareable', | ||
locations: [DirectiveLocation.OBJECT, DirectiveLocation.FIELD_DEFINITION], | ||
}); | ||
const legacyFederationTypes = [ | ||
fieldSetTypeSpec, | ||
]; | ||
export const overrideDirectiveSpec = createDirectiveSpecification({ | ||
name: 'override', | ||
locations: [DirectiveLocation.FIELD_DEFINITION], | ||
argumentFct: (schema) => ({ | ||
args: [{ name: 'from', type: new NonNullType(schema.stringType()) }], | ||
errors: [], | ||
}), | ||
}); | ||
const legacyFederationDirectives = [ | ||
keyDirectiveSpec, | ||
requiresDirectiveSpec, | ||
providesDirectiveSpec, | ||
externalDirectiveSpec, | ||
TAG_VERSIONS.latest().tagDirectiveSpec, | ||
extendsDirectiveSpec, | ||
]; | ||
export const composeDirectiveSpec = createDirectiveSpecification({ | ||
name: 'composeDirective', | ||
locations: [DirectiveLocation.SCHEMA], | ||
repeatable: true, | ||
argumentFct: (schema) => ({ | ||
args: [{ name: 'name', type: schema.stringType() }], | ||
errors: [], | ||
}), | ||
}) | ||
export const FEDERATION1_TYPES = legacyFederationTypes; | ||
export const FEDERATION1_DIRECTIVES = legacyFederationDirectives; | ||
@@ -109,48 +119,63 @@ function fieldsArgument(schema: Schema): ArgumentSpecification { | ||
export const FEDERATION2_ONLY_SPEC_DIRECTIVES = [ | ||
shareableDirectiveSpec, | ||
INACCESSIBLE_VERSIONS.latest().inaccessibleDirectiveSpec, | ||
overrideDirectiveSpec, | ||
]; | ||
export class FederationSpecDefinition extends FeatureDefinition { | ||
private readonly _directiveSpecs = new MapWithCachedArrays<string, DirectiveSpecification>(); | ||
private readonly _typeSpecs = new MapWithCachedArrays<string, TypeSpecification>(); | ||
export const FEDERATION2_1_ONLY_SPEC_DIRECTIVES = [ | ||
composeDirectiveSpec, | ||
]; | ||
constructor(version: FeatureVersion) { | ||
super(new FeatureUrl(federationIdentity, 'federation', version)); | ||
const PRE_FEDERATION2_SPEC_DIRECTIVES = [ | ||
keyDirectiveSpec, | ||
requiresDirectiveSpec, | ||
providesDirectiveSpec, | ||
externalDirectiveSpec, | ||
TAG_VERSIONS.latest().tagDirectiveSpec, | ||
extendsDirectiveSpec, // TODO: should we stop supporting that? | ||
]; | ||
for (const type of legacyFederationTypes) { | ||
this.registerType(type); | ||
} | ||
// Note that this is only used for federation 2+ (federation 1 adds the same directive, but not through a core spec). | ||
export const FEDERATION2_SPEC_DIRECTIVES = [ | ||
...PRE_FEDERATION2_SPEC_DIRECTIVES, | ||
...FEDERATION2_ONLY_SPEC_DIRECTIVES, | ||
...FEDERATION2_1_ONLY_SPEC_DIRECTIVES, | ||
]; | ||
for (const directive of legacyFederationDirectives) { | ||
this.registerDirective(directive); | ||
} | ||
// Note that this is meant to contain _all_ federation directive names ever supported, regardless of which version. | ||
// But currently, fed2 directives are a superset of fed1's so ... (but this may change if we stop supporting `@extends` | ||
// in fed2). | ||
export const ALL_FEDERATION_DIRECTIVES_DEFAULT_NAMES = FEDERATION2_SPEC_DIRECTIVES.map((spec) => spec.name); | ||
this.registerDirective(createDirectiveSpecification({ | ||
name: FederationDirectiveName.SHAREABLE, | ||
locations: [DirectiveLocation.OBJECT, DirectiveLocation.FIELD_DEFINITION], | ||
repeatable: version >= (new FeatureVersion(2, 2)), | ||
})); | ||
export const FEDERATION_SPEC_TYPES = [ | ||
fieldSetTypeSpec, | ||
] | ||
this.registerDirective(INACCESSIBLE_VERSIONS.latest().inaccessibleDirectiveSpec); | ||
export class FederationSpecDefinition extends FeatureDefinition { | ||
constructor(version: FeatureVersion) { | ||
super(new FeatureUrl(federationIdentity, 'federation', version)); | ||
this.registerDirective(createDirectiveSpecification({ | ||
name: FederationDirectiveName.OVERRIDE, | ||
locations: [DirectiveLocation.FIELD_DEFINITION], | ||
argumentFct: (schema) => ({ | ||
args: [{ name: 'from', type: new NonNullType(schema.stringType()) }], | ||
errors: [], | ||
}), | ||
})); | ||
if (version >= (new FeatureVersion(2, 1))) { | ||
this.registerDirective(createDirectiveSpecification({ | ||
name: FederationDirectiveName.COMPOSE_DIRECTIVE, | ||
locations: [DirectiveLocation.SCHEMA], | ||
repeatable: true, | ||
argumentFct: (schema) => ({ | ||
args: [{ name: 'name', type: schema.stringType() }], | ||
errors: [], | ||
}), | ||
})); | ||
} | ||
} | ||
private allFedDirectives(): DirectiveSpecification[] { | ||
return PRE_FEDERATION2_SPEC_DIRECTIVES | ||
.concat(FEDERATION2_ONLY_SPEC_DIRECTIVES) | ||
.concat(this.url.version >= (new FeatureVersion(2, 1)) ? FEDERATION2_1_ONLY_SPEC_DIRECTIVES : []); | ||
private registerDirective(spec: DirectiveSpecification) { | ||
this._directiveSpecs.set(spec.name, spec); | ||
} | ||
private registerType(spec: TypeSpecification) { | ||
this._typeSpecs.set(spec.name, spec); | ||
} | ||
directiveSpecs(): readonly DirectiveSpecification[] { | ||
return this._directiveSpecs.values(); | ||
} | ||
typeSpecs(): readonly TypeSpecification[] { | ||
return this._typeSpecs.values(); | ||
} | ||
addElementsToSchema(schema: Schema): GraphQLError[] { | ||
@@ -161,5 +186,7 @@ const feature = this.featureInSchema(schema); | ||
let errors: GraphQLError[] = []; | ||
errors = errors.concat(this.addTypeSpec(schema, fieldSetTypeSpec)); | ||
for (const type of this.typeSpecs()) { | ||
errors = errors.concat(this.addTypeSpec(schema, type)); | ||
} | ||
for (const directive of this.allFedDirectives()) { | ||
for (const directive of this.directiveSpecs()) { | ||
errors = errors.concat(this.addDirectiveSpec(schema, directive)); | ||
@@ -171,5 +198,4 @@ } | ||
allElementNames(): string[] { | ||
return this.allFedDirectives().map((spec) => `@${spec.name}`).concat([ | ||
fieldSetTypeSpec.name, | ||
]) | ||
return this.directiveSpecs().map((spec) => `@${spec.name}`) | ||
.concat(this.typeSpecs().map((spec) => spec.name)); | ||
} | ||
@@ -180,4 +206,5 @@ } | ||
.add(new FederationSpecDefinition(new FeatureVersion(2, 0))) | ||
.add(new FederationSpecDefinition(new FeatureVersion(2, 1))); | ||
.add(new FederationSpecDefinition(new FeatureVersion(2, 1))) | ||
.add(new FederationSpecDefinition(new FeatureVersion(2, 2))); | ||
registerKnownFeature(FEDERATION_VERSIONS); |
@@ -5,2 +5,12 @@ import { DirectiveLocation } from "graphql"; | ||
export const introspectionFieldNames = [ '__schema', '__type' ]; | ||
export const introspectionTypeNames = [ | ||
'__Schema', | ||
'__Directive', | ||
'__DirectiveLocation', | ||
'__Type', | ||
'__Field', | ||
'__InputValue', | ||
'__EnumValue', | ||
'__TypeKind', | ||
] | ||
@@ -7,0 +17,0 @@ export function isIntrospectionName(name: string): boolean { |
@@ -35,4 +35,4 @@ import { | ||
import { assert, firstOf, MultiMap } from "./utils"; | ||
import { FEDERATION_SPEC_TYPES } from "./federationSpec"; | ||
import { valueEquals } from "./values"; | ||
import { FEDERATION1_TYPES } from "./federationSpec"; | ||
@@ -63,2 +63,3 @@ export type UpgradeResult = UpgradeSuccess | UpgradeFailure; | ||
| ExternalOnInterfaceRemoval | ||
| ExternalOnObjectTypeRemoval | ||
| InactiveProvidesOrRequiresRemoval | ||
@@ -105,2 +106,12 @@ | InactiveProvidesOrRequiresFieldsRemoval | ||
export class ExternalOnObjectTypeRemoval { | ||
readonly id = 'EXTERNAL_ON_OBJECT_TYPE_REMOVAL' as const; | ||
constructor(readonly type: string) {} | ||
toString() { | ||
return `Removed @external directive on object type "${this.type}": @external on types was not rejected but was inactive in fed1`; | ||
} | ||
} | ||
export class UnusedExternalRemoval { | ||
@@ -336,3 +347,3 @@ readonly id = 'UNUSED_EXTERNAL_REMOVAL' as const; | ||
// type names (relying on the core schema prefixing instead) and so some special translation needs to happen. | ||
for (const typeSpec of FEDERATION_SPEC_TYPES) { | ||
for (const typeSpec of FEDERATION1_TYPES) { | ||
const typeNameInOriginal = this.originalSubgraph.metadata().federationTypeNameInSchema(typeSpec.name); | ||
@@ -389,2 +400,3 @@ const type = this.schema.type(typeNameInOriginal); | ||
this.removeExternalOnInterface(); | ||
this.removeExternalOnObjectTypes(); | ||
@@ -492,2 +504,12 @@ // Note that we remove all external on type extensions first, so we don't have to care about it later in @key, @provides and @requires. | ||
private removeExternalOnObjectTypes() { | ||
for (const type of this.schema.objectTypes()) { | ||
const external = type.appliedDirectivesOf(this.metadata.externalDirective())[0]; | ||
if (external) { | ||
this.addChange(new ExternalOnObjectTypeRemoval(type.coordinate)); | ||
external.remove(); | ||
} | ||
} | ||
} | ||
private replaceFederationDirectiveApplication( | ||
@@ -494,0 +516,0 @@ application: Directive<SchemaElement<any, any>, {fields: any}>, |
@@ -170,2 +170,17 @@ /** | ||
/** | ||
* Whether the first set is a (non-strict) subset of the second set. | ||
*/ | ||
export function isSubset<T>(superset: Set<T>, maybeSubset: Set<T>): boolean { | ||
if (superset === maybeSubset) { | ||
return true; | ||
} | ||
for (const elt of maybeSubset) { | ||
if (!superset.has(elt)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
export function firstOf<T>(iterable: Iterable<T>): T | undefined { | ||
@@ -172,0 +187,0 @@ const res = iterable[Symbol.iterator]().next(); |
@@ -21,3 +21,3 @@ import { | ||
import { isValidValue, valueToString } from "./values"; | ||
import { isIntrospectionName } from "./introspection"; | ||
import { introspectionTypeNames, isIntrospectionName } from "./introspection"; | ||
import { isSubtype, sameType } from "./types"; | ||
@@ -83,3 +83,6 @@ import { ERRORS } from "./error"; | ||
for (const type of this.schema.types()) { | ||
this.validateName(type); | ||
if (!introspectionTypeNames.includes(type.name)) { | ||
this.validateName(type); | ||
} | ||
switch (type.kind) { | ||
@@ -151,2 +154,6 @@ case 'ObjectType': | ||
if (isIntrospectionName(elt.name)) { | ||
this.addError( | ||
`Name "${elt.name}" must not begin with "__", which is reserved by GraphQL introspection.`, | ||
elt.sourceAST ? { nodes: elt.sourceAST } : {} | ||
); | ||
return; | ||
@@ -153,0 +160,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1987283
33481