@apollo/federation-internals
Advanced tools
Comparing version 2.9.0-connectors.9 to 2.10.0-alpha.0
@@ -37,4 +37,21 @@ import { InputType, Schema } from "./definitions"; | ||
}; | ||
NULLABLE_AND: { | ||
name: string; | ||
isTypeSupported: TypeSupportValidator; | ||
mergeValues: (values: (boolean | null | undefined)[]) => boolean | null | undefined; | ||
}; | ||
NULLABLE_MAX: { | ||
name: string; | ||
isTypeSupported: TypeSupportValidator; | ||
mergeValues: (values: any[]) => any; | ||
}; | ||
NULLABLE_UNION: { | ||
name: string; | ||
isTypeSupported: (_: Schema, type: InputType) => { | ||
valid: boolean; | ||
}; | ||
mergeValues: (values: any[]) => unknown[] | undefined; | ||
}; | ||
}; | ||
export {}; | ||
//# sourceMappingURL=argumentCompositionStrategies.d.ts.map |
@@ -53,3 +53,41 @@ "use strict"; | ||
}, | ||
NULLABLE_AND: { | ||
name: 'NULLABLE_AND', | ||
isTypeSupported: supportFixedTypes((schema) => [schema.booleanType()]), | ||
mergeValues: (values) => values.reduce((acc, next) => { | ||
if (acc === null || acc === undefined) { | ||
return next; | ||
} | ||
else if (next === null || next === undefined) { | ||
return acc; | ||
} | ||
else { | ||
return acc && next; | ||
} | ||
}, undefined), | ||
}, | ||
NULLABLE_MAX: { | ||
name: 'NULLABLE_MAX', | ||
isTypeSupported: supportFixedTypes((schema) => [schema.intType(), new definitions_1.NonNullType(schema.intType())]), | ||
mergeValues: (values) => values.reduce((a, b) => a !== undefined && b !== undefined ? Math.max(a, b) : a !== null && a !== void 0 ? a : b, undefined), | ||
}, | ||
NULLABLE_UNION: { | ||
name: 'NULLABLE_UNION', | ||
isTypeSupported: (_, type) => ({ valid: (0, definitions_1.isListType)(type) }), | ||
mergeValues: (values) => { | ||
if (values.every((v) => v === undefined)) { | ||
return undefined; | ||
} | ||
const combined = new Set(); | ||
for (const subgraphValues of values) { | ||
if (Array.isArray(subgraphValues)) { | ||
for (const value of subgraphValues) { | ||
combined.add(value); | ||
} | ||
} | ||
} | ||
return Array.from(combined); | ||
} | ||
} | ||
}; | ||
//# sourceMappingURL=argumentCompositionStrategies.js.map |
@@ -159,2 +159,3 @@ "use strict"; | ||
const types = filteredTypes(supergraph, joinSpec, coreFeatures.coreDefinition); | ||
const originalDirectiveNames = getApolloDirectiveNames(supergraph); | ||
const args = { | ||
@@ -165,2 +166,3 @@ supergraph, | ||
filteredTypes: types, | ||
originalDirectiveNames, | ||
getSubgraph, | ||
@@ -238,3 +240,4 @@ getSubgraphEnumValue, | ||
(0, utils_1.assert)(subgraph, () => `Should have found the subgraph for ${application}`); | ||
subgraph.schema.addType((0, definitions_1.newNamedType)(type.kind, type.name)); | ||
const subgraphType = subgraph.schema.addType((0, definitions_1.newNamedType)(type.kind, type.name)); | ||
propagateDemandControlDirectives(type, subgraphType, subgraph, args.originalDirectiveNames); | ||
} | ||
@@ -306,2 +309,3 @@ break; | ||
(0, utils_1.assert)(implementsDirective, '@join__implements should existing for a fed2 supergraph'); | ||
const originalDirectiveNames = args.originalDirectiveNames; | ||
for (const { type, subgraphsInfo } of info) { | ||
@@ -314,2 +318,5 @@ const implementsApplications = type.appliedDirectivesOf(implementsDirective); | ||
} | ||
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) { | ||
propagateDemandControlDirectives(type, subgraphType, subgraph, args.originalDirectiveNames); | ||
} | ||
for (const field of type.fields()) { | ||
@@ -320,3 +327,3 @@ const fieldApplications = field.appliedDirectivesOf(fieldDirective); | ||
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) { | ||
addSubgraphField({ field, type: subgraphType, subgraph, isShareable }); | ||
addSubgraphField({ field, type: subgraphType, subgraph, isShareable, originalDirectiveNames }); | ||
} | ||
@@ -336,3 +343,3 @@ } | ||
const { type: subgraphType, subgraph } = subgraphsInfo.get(joinFieldArgs.graph); | ||
addSubgraphField({ field, type: subgraphType, subgraph, isShareable, joinFieldArgs }); | ||
addSubgraphField({ field, type: subgraphType, subgraph, isShareable, joinFieldArgs, originalDirectiveNames }); | ||
} | ||
@@ -343,4 +350,25 @@ } | ||
} | ||
function getApolloDirectiveNames(supergraph) { | ||
const originalDirectiveNames = {}; | ||
for (const linkDirective of supergraph.schemaDefinition.appliedDirectivesOf("link")) { | ||
if (linkDirective.arguments().url && linkDirective.arguments().import) { | ||
const url = _1.FeatureUrl.maybeParse(linkDirective.arguments().url); | ||
if (!(url === null || url === void 0 ? void 0 : url.identity.includes("specs.apollo.dev"))) { | ||
continue; | ||
} | ||
for (const importedDirective of linkDirective.arguments().import) { | ||
if (importedDirective.name && importedDirective.as) { | ||
originalDirectiveNames[importedDirective.name.replace('@', '')] = importedDirective.as.replace('@', ''); | ||
} | ||
else if (typeof importedDirective === 'string') { | ||
originalDirectiveNames[importedDirective.replace('@', '')] = importedDirective.replace('@', ''); | ||
} | ||
} | ||
} | ||
} | ||
return originalDirectiveNames; | ||
} | ||
function extractInputObjContent(args, info) { | ||
const fieldDirective = args.joinSpec.fieldDirective(args.supergraph); | ||
const originalDirectiveNames = args.originalDirectiveNames; | ||
for (const { type, subgraphsInfo } of info) { | ||
@@ -351,3 +379,3 @@ for (const field of type.fields()) { | ||
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) { | ||
addSubgraphInputField({ field, type: subgraphType, subgraph }); | ||
addSubgraphInputField({ field, type: subgraphType, subgraph, originalDirectiveNames }); | ||
} | ||
@@ -362,3 +390,3 @@ } | ||
const { type: subgraphType, subgraph } = subgraphsInfo.get(args.graph); | ||
addSubgraphInputField({ field, type: subgraphType, subgraph, joinFieldArgs: args }); | ||
addSubgraphInputField({ field, type: subgraphType, subgraph, joinFieldArgs: args, originalDirectiveNames }); | ||
} | ||
@@ -371,3 +399,7 @@ } | ||
const enumValueDirective = args.joinSpec.enumValueDirective(args.supergraph); | ||
const originalDirectiveNames = args.originalDirectiveNames; | ||
for (const { type, subgraphsInfo } of info) { | ||
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) { | ||
propagateDemandControlDirectives(type, subgraphType, subgraph, originalDirectiveNames); | ||
} | ||
for (const value of type.values) { | ||
@@ -452,2 +484,18 @@ const enumValueApplications = enumValueDirective ? value.appliedDirectivesOf(enumValueDirective) : []; | ||
} | ||
function propagateDemandControlDirectives(source, dest, subgraph, originalDirectiveNames) { | ||
const costDirectiveName = originalDirectiveNames === null || originalDirectiveNames === void 0 ? void 0 : originalDirectiveNames[_1.FederationDirectiveName.COST]; | ||
if (costDirectiveName) { | ||
const costDirective = source.appliedDirectivesOf(costDirectiveName).pop(); | ||
if (costDirective) { | ||
dest.applyDirective(subgraph.metadata().costDirective().name, costDirective.arguments()); | ||
} | ||
} | ||
const listSizeDirectiveName = originalDirectiveNames === null || originalDirectiveNames === void 0 ? void 0 : originalDirectiveNames[_1.FederationDirectiveName.LIST_SIZE]; | ||
if (listSizeDirectiveName) { | ||
const listSizeDirective = source.appliedDirectivesOf(listSizeDirectiveName).pop(); | ||
if (listSizeDirective) { | ||
dest.applyDirective(subgraph.metadata().listSizeDirective().name, listSizeDirective.arguments()); | ||
} | ||
} | ||
} | ||
function errorToString(e) { | ||
@@ -457,3 +505,3 @@ const causes = (0, _1.errorCauses)(e); | ||
} | ||
function addSubgraphField({ field, type, subgraph, isShareable, joinFieldArgs, }) { | ||
function addSubgraphField({ field, type, subgraph, isShareable, joinFieldArgs, originalDirectiveNames, }) { | ||
const copiedFieldType = (joinFieldArgs === null || joinFieldArgs === void 0 ? void 0 : joinFieldArgs.type) | ||
@@ -464,3 +512,4 @@ ? decodeType(joinFieldArgs.type, subgraph.schema, subgraph.name) | ||
for (const arg of field.arguments()) { | ||
subgraphField.addArgument(arg.name, copyType(arg.type, subgraph.schema, subgraph.name), arg.defaultValue); | ||
const argDef = subgraphField.addArgument(arg.name, copyType(arg.type, subgraph.schema, subgraph.name), arg.defaultValue); | ||
propagateDemandControlDirectives(arg, argDef, subgraph, originalDirectiveNames); | ||
} | ||
@@ -509,5 +558,6 @@ if (joinFieldArgs === null || joinFieldArgs === void 0 ? void 0 : joinFieldArgs.requires) { | ||
} | ||
propagateDemandControlDirectives(field, subgraphField, subgraph, originalDirectiveNames); | ||
return subgraphField; | ||
} | ||
function addSubgraphInputField({ field, type, subgraph, joinFieldArgs, }) { | ||
function addSubgraphInputField({ field, type, subgraph, joinFieldArgs, originalDirectiveNames, }) { | ||
const copiedType = (joinFieldArgs === null || joinFieldArgs === void 0 ? void 0 : joinFieldArgs.type) | ||
@@ -518,2 +568,3 @@ ? decodeType(joinFieldArgs === null || joinFieldArgs === void 0 ? void 0 : joinFieldArgs.type, subgraph.schema, subgraph.name) | ||
inputField.defaultValue = field.defaultValue; | ||
propagateDemandControlDirectives(field, inputField, subgraph, originalDirectiveNames); | ||
return inputField; | ||
@@ -520,0 +571,0 @@ } |
@@ -7,2 +7,3 @@ import { CompositeType, CoreFeature, Directive, DirectiveDefinition, FieldDefinition, InputFieldDefinition, InterfaceType, NamedType, ObjectType, ScalarType, Schema, SchemaBlueprint, SchemaConfig, SchemaElement, UnionType } from "./definitions"; | ||
import { PrintOptions as PrintOptions } from "./print"; | ||
import { CostDirectiveArguments, ListSizeDirectiveArguments } from "./specs/costSpec"; | ||
export declare const FEDERATION_RESERVED_SUBGRAPH_NAME = "_"; | ||
@@ -84,2 +85,4 @@ export declare const FEDERATION_UNNAMED_SUBGRAPH_NAME = "<unnamed>"; | ||
}>; | ||
costDirective(): Post20FederationDirectiveDefinition<CostDirectiveArguments>; | ||
listSizeDirective(): Post20FederationDirectiveDefinition<ListSizeDirectiveArguments>; | ||
allFederationDirectives(): DirectiveDefinition[]; | ||
@@ -120,4 +123,4 @@ entityType(): UnionType | undefined; | ||
export declare function setSchemaAsFed2Subgraph(schema: Schema, useLatest?: boolean): void; | ||
export declare const FEDERATION2_LINK_WITH_FULL_IMPORTS = "@link(url: \"https://specs.apollo.dev/federation/v2.8\", import: [\"@key\", \"@requires\", \"@provides\", \"@external\", \"@tag\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@composeDirective\", \"@interfaceObject\", \"@authenticated\", \"@requiresScopes\", \"@policy\", \"@context\", \"@fromContext\"])"; | ||
export declare const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS = "@link(url: \"https://specs.apollo.dev/federation/v2.8\", import: [\"@key\", \"@requires\", \"@provides\", \"@external\", \"@tag\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@composeDirective\", \"@interfaceObject\"])"; | ||
export declare const FEDERATION2_LINK_WITH_FULL_IMPORTS = "@link(url: \"https://specs.apollo.dev/federation/v2.10\", import: [\"@key\", \"@requires\", \"@provides\", \"@external\", \"@tag\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@composeDirective\", \"@interfaceObject\", \"@authenticated\", \"@requiresScopes\", \"@policy\", \"@context\", \"@fromContext\", \"@cost\", \"@listSize\"])"; | ||
export declare const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS = "@link(url: \"https://specs.apollo.dev/federation/v2.10\", import: [\"@key\", \"@requires\", \"@provides\", \"@external\", \"@tag\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@composeDirective\", \"@interfaceObject\"])"; | ||
export declare const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS_UPGRADED = "@link(url: \"https://specs.apollo.dev/federation/v2.4\", import: [\"@key\", \"@requires\", \"@provides\", \"@external\", \"@tag\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@composeDirective\", \"@interfaceObject\"])"; | ||
@@ -124,0 +127,0 @@ export declare function asFed2SubgraphDocument(document: DocumentNode, options?: { |
@@ -28,2 +28,3 @@ export * from './definitions'; | ||
export * from './specs/connectSpec'; | ||
export * from './specs/costSpec'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -46,2 +46,3 @@ "use strict"; | ||
__exportStar(require("./specs/connectSpec"), exports); | ||
__exportStar(require("./specs/costSpec"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -180,3 +180,22 @@ "use strict"; | ||
const subgraphsUsingInterfaceObject = []; | ||
const objectTypeMap = new Map(); | ||
for (const subgraph of inputs.values()) { | ||
for (const t of subgraph.schema.objectTypes()) { | ||
let entry = objectTypeMap.get(t.name); | ||
if (!entry) { | ||
entry = new Map(); | ||
objectTypeMap.set(t.name, entry); | ||
} | ||
entry.set(subgraph.name, [t, subgraph.metadata()]); | ||
} | ||
for (const t of subgraph.schema.interfaceTypes()) { | ||
let entry = objectTypeMap.get(t.name); | ||
if (!entry) { | ||
entry = new Map(); | ||
objectTypeMap.set(t.name, entry); | ||
} | ||
entry.set(subgraph.name, [t, subgraph.metadata()]); | ||
} | ||
} | ||
for (const subgraph of inputs.values()) { | ||
if (subgraph.isFed2Subgraph()) { | ||
@@ -189,4 +208,3 @@ subgraphs.add(subgraph); | ||
else { | ||
const otherSubgraphs = inputs.values().filter((s) => s.name !== subgraph.name); | ||
const res = new SchemaUpgrader(subgraph, otherSubgraphs).upgrade(); | ||
const res = new SchemaUpgrader(subgraph, inputs.values(), objectTypeMap).upgrade(); | ||
if (res.errors) { | ||
@@ -224,11 +242,2 @@ errors = errors.concat(res.errors); | ||
} | ||
function resolvesField(subgraph, field) { | ||
const metadata = subgraph.metadata(); | ||
const t = subgraph.schema.type(field.parent.name); | ||
if (!t || !(0, definitions_1.isObjectType)(t)) { | ||
return false; | ||
} | ||
const f = t.field(field.name); | ||
return !!f && (!metadata.isFieldExternal(f) || metadata.isFieldPartiallyExternal(f)); | ||
} | ||
function getField(schema, typeName, fieldName) { | ||
@@ -239,5 +248,6 @@ const type = schema.type(typeName); | ||
class SchemaUpgrader { | ||
constructor(originalSubgraph, otherSubgraphs) { | ||
constructor(originalSubgraph, allSubgraphs, objectTypeMap) { | ||
this.originalSubgraph = originalSubgraph; | ||
this.otherSubgraphs = otherSubgraphs; | ||
this.allSubgraphs = allSubgraphs; | ||
this.objectTypeMap = objectTypeMap; | ||
this.changes = new utils_1.MultiMap(); | ||
@@ -287,4 +297,5 @@ this.errors = []; | ||
const extensionAST = (_a = (0, utils_1.firstOf)(type.extensions().values())) === null || _a === void 0 ? void 0 : _a.sourceAST; | ||
for (const subgraph of this.otherSubgraphs) { | ||
const otherType = subgraph.schema.type(type.name); | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name).entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
for (let i = 0; i < typeInOtherSubgraphs.length; i += 1) { | ||
const otherType = typeInOtherSubgraphs[i][1][0]; | ||
if (otherType && otherType.hasNonExtensionElements()) { | ||
@@ -433,9 +444,7 @@ return; | ||
else { | ||
for (const other of this.otherSubgraphs) { | ||
const typeInOther = other.schema.type(type.name); | ||
if (!typeInOther) { | ||
continue; | ||
} | ||
(0, utils_1.assert)((0, definitions_1.isCompositeType)(typeInOther), () => `Type ${type} is of kind ${type.kind} in ${this.subgraph.name} but ${typeInOther.kind} in ${other.name}`); | ||
const keysInOther = typeInOther.appliedDirectivesOf(other.metadata().keyDirective()); | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name).entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
for (const [otherSubgraphName, v] of typeInOtherSubgraphs) { | ||
const [typeInOther, metadata] = v; | ||
(0, utils_1.assert)((0, definitions_1.isCompositeType)(typeInOther), () => `Type ${type} is of kind ${type.kind} in ${this.subgraph.name} but ${typeInOther.kind} in ${otherSubgraphName}`); | ||
const keysInOther = typeInOther.appliedDirectivesOf(metadata.keyDirective()); | ||
if (keysInOther.length === 0) { | ||
@@ -532,3 +541,6 @@ continue; | ||
for (const type of this.schema.objectTypes()) { | ||
if (type.hasAppliedDirective(keyDirective) || type.isRootType()) { | ||
if (type.isSubscriptionRootType()) { | ||
continue; | ||
} | ||
if (type.hasAppliedDirective(keyDirective) || (type.isRootType())) { | ||
for (const field of type.fields()) { | ||
@@ -538,6 +550,13 @@ if (originalMetadata.isFieldShareable(field)) { | ||
} | ||
const otherResolvingSubgraphs = this.otherSubgraphs.filter((s) => resolvesField(s, field)); | ||
if (otherResolvingSubgraphs.length > 0 && !field.hasAppliedDirective(shareableDirective)) { | ||
const entries = Array.from(this.objectTypeMap.get(type.name).entries()); | ||
const typeInOtherSubgraphs = entries.filter(([subgraphName, v]) => { | ||
if (subgraphName === this.subgraph.name) { | ||
return false; | ||
} | ||
const f = v[0].field(field.name); | ||
return !!f && (!v[1].isFieldExternal(f) || v[1].isFieldPartiallyExternal(f)); | ||
}); | ||
if (typeInOtherSubgraphs.length > 0 && !field.hasAppliedDirective(shareableDirective)) { | ||
field.applyDirective(shareableDirective); | ||
this.addChange(new ShareableFieldAddition(field.coordinate, otherResolvingSubgraphs.map((s) => s.name))); | ||
this.addChange(new ShareableFieldAddition(field.coordinate, typeInOtherSubgraphs.map(([s]) => s))); | ||
} | ||
@@ -547,6 +566,6 @@ } | ||
else { | ||
const otherDeclaringSubgraphs = this.otherSubgraphs.filter((s) => s.schema.type(type.name)); | ||
if (otherDeclaringSubgraphs.length > 0 && !type.hasAppliedDirective(shareableDirective)) { | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name).entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
if (typeInOtherSubgraphs.length > 0 && !type.hasAppliedDirective(shareableDirective)) { | ||
type.applyDirective(shareableDirective); | ||
this.addChange(new ShareableTypeAddition(type.coordinate, otherDeclaringSubgraphs.map((s) => s.name))); | ||
this.addChange(new ShareableTypeAddition(type.coordinate, typeInOtherSubgraphs.map(([s]) => s))); | ||
} | ||
@@ -567,4 +586,4 @@ } | ||
if (this.external(element)) { | ||
const tagIsUsedInOtherDefinition = this.otherSubgraphs | ||
.map((s) => getField(s.schema, element.parent.name, element.name)) | ||
const tagIsUsedInOtherDefinition = this.allSubgraphs | ||
.map((s) => s.name === this.originalSubgraph.name ? undefined : getField(s.schema, element.parent.name, element.name)) | ||
.filter((f) => !(f && f.hasAppliedDirective('external'))) | ||
@@ -571,0 +590,0 @@ .some((f) => f && f.appliedDirectivesOf('tag').some((d) => (0, values_1.valueEquals)(application.arguments(), d.arguments()))); |
@@ -11,33 +11,3 @@ import { GraphQLError } from 'graphql'; | ||
} | ||
export type SourceDirectiveArgs = { | ||
name: string; | ||
http: SourceDirectiveHTTP; | ||
}; | ||
export type SourceDirectiveHTTP = { | ||
baseURL: string; | ||
headers?: HTTPHeaderMapping[]; | ||
}; | ||
type HTTPHeaderMapping = { | ||
name: string; | ||
as?: string; | ||
value?: string; | ||
}; | ||
type URLPathTemplate = string; | ||
type JSONSelection = string; | ||
export type ConnectDirectiveArgs = { | ||
source: string; | ||
http: ConnectDirectiveHTTP; | ||
selection?: JSONSelection; | ||
}; | ||
export type ConnectDirectiveHTTP = { | ||
GET?: URLPathTemplate; | ||
POST?: URLPathTemplate; | ||
PUT?: URLPathTemplate; | ||
PATCH?: URLPathTemplate; | ||
DELETE?: URLPathTemplate; | ||
body?: JSONSelection; | ||
headers?: HTTPHeaderMapping[]; | ||
}; | ||
export declare const CONNECT_VERSIONS: FeatureDefinitions<ConnectSpecDefinition>; | ||
export {}; | ||
//# sourceMappingURL=connectSpec.d.ts.map |
@@ -33,4 +33,4 @@ "use strict"; | ||
})); | ||
this.registerType({ name: URL_PATH_TEMPLATE, checkOrAdd: () => [] }); | ||
this.registerType({ name: JSON_SELECTION, checkOrAdd: () => [] }); | ||
this.registerType((0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name: URL_PATH_TEMPLATE })); | ||
this.registerType((0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name: JSON_SELECTION })); | ||
this.registerType({ name: CONNECT_HTTP, checkOrAdd: () => [] }); | ||
@@ -82,4 +82,4 @@ this.registerType({ name: SOURCE_HTTP, checkOrAdd: () => [] }); | ||
exports.CONNECT_VERSIONS = new coreSpec_1.FeatureDefinitions(exports.connectIdentity) | ||
.add(new ConnectSpecDefinition(new coreSpec_1.FeatureVersion(0, 1), new coreSpec_1.FeatureVersion(2, 9))); | ||
.add(new ConnectSpecDefinition(new coreSpec_1.FeatureVersion(0, 1), new coreSpec_1.FeatureVersion(2, 10))); | ||
(0, knownCoreFeatures_1.registerKnownFeature)(exports.CONNECT_VERSIONS); | ||
//# sourceMappingURL=connectSpec.js.map |
@@ -82,2 +82,3 @@ import { ASTNode, GraphQLError, StringValueNode } from "graphql"; | ||
applyFeatureToSchema(schema: Schema, feature: FeatureDefinition, as?: string, purpose?: CorePurpose): GraphQLError[]; | ||
applyFeatureAsLink(schema: Schema, feature: FeatureDefinition, purpose?: CorePurpose, imports?: CoreImport[]): GraphQLError[]; | ||
extractFeatureUrl(args: CoreOrLinkDirectiveArgs): FeatureUrl; | ||
@@ -84,0 +85,0 @@ urlArgName(): 'feature' | 'url'; |
@@ -393,2 +393,20 @@ "use strict"; | ||
} | ||
applyFeatureAsLink(schema, feature, purpose, imports) { | ||
var _a; | ||
const existing = schema.schemaDefinition.appliedDirectivesOf(exports.linkDirectiveDefaultName).find((link) => link.arguments().url === feature.toString()); | ||
if (existing) { | ||
existing.remove(); | ||
} | ||
const coreDirective = this.coreDirective(schema); | ||
const args = { | ||
url: feature.toString(), | ||
import: ((_a = existing === null || existing === void 0 ? void 0 : existing.arguments().import) !== null && _a !== void 0 ? _a : []).concat(imports === null || imports === void 0 ? void 0 : imports.map((i) => i.as ? { name: `@${i.name}`, as: `@${i.as}` } : `@${i.name}`)), | ||
feature: undefined, | ||
}; | ||
if (this.supportPurposes() && purpose) { | ||
args.for = purpose; | ||
} | ||
schema.schemaDefinition.applyDirective(coreDirective, args); | ||
return feature.addElementsToSchema(schema); | ||
} | ||
extractFeatureUrl(args) { | ||
@@ -430,3 +448,3 @@ return FeatureUrl.parse(args[this.urlArgName()]); | ||
var _a; | ||
const def = this._definitions.find(def => def.minimumFederationVersion ? fedVersion >= def.minimumFederationVersion : true); | ||
const def = this._definitions.find(def => def.minimumFederationVersion ? fedVersion.gte(def.minimumFederationVersion) : true); | ||
(0, utils_1.assert)(def, `No compatible definition exists for federation version ${fedVersion}`); | ||
@@ -456,3 +474,3 @@ const latestMajor = this.latest().version.major; | ||
for (const version of versions) { | ||
if (!max || version > max) { | ||
if (!max || version.gt(max)) { | ||
max = version; | ||
@@ -459,0 +477,0 @@ } |
@@ -23,3 +23,5 @@ import { FeatureDefinition, FeatureDefinitions, FeatureVersion } from "./coreSpec"; | ||
CONTEXT = "context", | ||
FROM_CONTEXT = "fromContext" | ||
FROM_CONTEXT = "fromContext", | ||
COST = "cost", | ||
LIST_SIZE = "listSize" | ||
} | ||
@@ -26,0 +28,0 @@ export declare const FEDERATION1_TYPES: import("../directiveAndTypeSpecification").TypeSpecification[]; |
@@ -17,2 +17,3 @@ "use strict"; | ||
const contextSpec_1 = require("./contextSpec"); | ||
const costSpec_1 = require("./costSpec"); | ||
exports.federationIdentity = 'https://specs.apollo.dev/federation'; | ||
@@ -42,2 +43,4 @@ var FederationTypeName; | ||
FederationDirectiveName["FROM_CONTEXT"] = "fromContext"; | ||
FederationDirectiveName["COST"] = "cost"; | ||
FederationDirectiveName["LIST_SIZE"] = "listSize"; | ||
})(FederationDirectiveName || (exports.FederationDirectiveName = FederationDirectiveName = {})); | ||
@@ -107,3 +110,3 @@ const fieldSetTypeSpec = (0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name: FederationTypeName.FIELD_SET }); | ||
this.registerSubFeature(inaccessibleSpec_1.INACCESSIBLE_VERSIONS.getMinimumRequiredVersion(version)); | ||
if (version >= (new coreSpec_1.FeatureVersion(2, 7))) { | ||
if (version.gte(new coreSpec_1.FeatureVersion(2, 7))) { | ||
this.registerDirective((0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ | ||
@@ -150,2 +153,5 @@ name: FederationDirectiveName.OVERRIDE, | ||
} | ||
if (version.gte(new coreSpec_1.FeatureVersion(2, 9))) { | ||
this.registerSubFeature(costSpec_1.COST_VERSIONS.find(new coreSpec_1.FeatureVersion(0, 1))); | ||
} | ||
} | ||
@@ -163,4 +169,6 @@ } | ||
.add(new FederationSpecDefinition(new coreSpec_1.FeatureVersion(2, 7))) | ||
.add(new FederationSpecDefinition(new coreSpec_1.FeatureVersion(2, 8))); | ||
.add(new FederationSpecDefinition(new coreSpec_1.FeatureVersion(2, 8))) | ||
.add(new FederationSpecDefinition(new coreSpec_1.FeatureVersion(2, 9))) | ||
.add(new FederationSpecDefinition(new coreSpec_1.FeatureVersion(2, 10))); | ||
(0, knownCoreFeatures_1.registerKnownFeature)(exports.FEDERATION_VERSIONS); | ||
//# sourceMappingURL=federationSpec.js.map |
@@ -42,2 +42,4 @@ "use strict"; | ||
'https://specs.apollo.dev/context/v0.1', | ||
'https://specs.apollo.dev/cost/v0.1', | ||
'https://specs.apollo.dev/connect/v0.1', | ||
]); | ||
@@ -44,0 +46,0 @@ const coreVersionZeroDotOneUrl = coreSpec_1.FeatureUrl.parse('https://specs.apollo.dev/core/v0.1'); |
{ | ||
"name": "@apollo/federation-internals", | ||
"version": "2.9.0-connectors.9", | ||
"version": "2.10.0-alpha.0", | ||
"description": "Apollo Federation internal utilities", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -62,2 +62,39 @@ import { InputType, NonNullType, Schema, isListType, isNonNullType } from "./definitions" | ||
}, | ||
NULLABLE_AND: { | ||
name: 'NULLABLE_AND', | ||
isTypeSupported: supportFixedTypes((schema: Schema) => [schema.booleanType()]), | ||
mergeValues: (values: (boolean | null | undefined)[]) => values.reduce((acc, next) => { | ||
if (acc === null || acc === undefined) { | ||
return next; | ||
} else if (next === null || next === undefined) { | ||
return acc; | ||
} else { | ||
return acc && next; | ||
} | ||
}, undefined), | ||
}, | ||
NULLABLE_MAX: { | ||
name: 'NULLABLE_MAX', | ||
isTypeSupported: supportFixedTypes((schema: Schema) => [schema.intType(), new NonNullType(schema.intType())]), | ||
mergeValues: (values: any[]) => values.reduce((a: any, b: any) => a !== undefined && b !== undefined ? Math.max(a, b) : a ?? b, undefined), | ||
}, | ||
NULLABLE_UNION: { | ||
name: 'NULLABLE_UNION', | ||
isTypeSupported: (_: Schema, type: InputType) => ({ valid: isListType(type) }), | ||
mergeValues: (values: any[]) => { | ||
if (values.every((v) => v === undefined)) { | ||
return undefined; | ||
} | ||
const combined = new Set(); | ||
for (const subgraphValues of values) { | ||
if (Array.isArray(subgraphValues)) { | ||
for (const value of subgraphValues) { | ||
combined.add(value); | ||
} | ||
} | ||
} | ||
return Array.from(combined); | ||
} | ||
} | ||
} |
@@ -43,3 +43,3 @@ import { | ||
import { validateStringContainsBoolean } from "./utils"; | ||
import { CONTEXT_VERSIONS, ContextSpecDefinition, DirectiveDefinition, errorCauses, isFederationDirectiveDefinedInSchema, printErrors } from "."; | ||
import { CONTEXT_VERSIONS, ContextSpecDefinition, DirectiveDefinition, FeatureUrl, FederationDirectiveName, SchemaElement, errorCauses, isFederationDirectiveDefinedInSchema, printErrors } from "."; | ||
@@ -228,2 +228,3 @@ function filteredTypes( | ||
const types = filteredTypes(supergraph, joinSpec, coreFeatures.coreDefinition); | ||
const originalDirectiveNames = getApolloDirectiveNames(supergraph); | ||
const args: ExtractArguments = { | ||
@@ -234,2 +235,3 @@ supergraph, | ||
filteredTypes: types, | ||
originalDirectiveNames, | ||
getSubgraph, | ||
@@ -298,2 +300,3 @@ getSubgraphEnumValue, | ||
filteredTypes: NamedType[], | ||
originalDirectiveNames: Record<string, string>, | ||
getSubgraph: (application: Directive<any, { graph?: string }>) => Subgraph | undefined, | ||
@@ -355,3 +358,4 @@ getSubgraphEnumValue: (subgraphName: string) => string | ||
assert(subgraph, () => `Should have found the subgraph for ${application}`); | ||
subgraph.schema.addType(newNamedType(type.kind, type.name)); | ||
const subgraphType = subgraph.schema.addType(newNamedType(type.kind, type.name)); | ||
propagateDemandControlDirectives(type, subgraphType, subgraph, args.originalDirectiveNames); | ||
} | ||
@@ -442,2 +446,4 @@ break; | ||
const originalDirectiveNames = args.originalDirectiveNames; | ||
for (const { type, subgraphsInfo } of info) { | ||
@@ -453,2 +459,6 @@ const implementsApplications = type.appliedDirectivesOf(implementsDirective); | ||
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) { | ||
propagateDemandControlDirectives(type, subgraphType, subgraph, args.originalDirectiveNames); | ||
} | ||
for (const field of type.fields()) { | ||
@@ -460,3 +470,3 @@ const fieldApplications = field.appliedDirectivesOf(fieldDirective); | ||
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) { | ||
addSubgraphField({ field, type: subgraphType, subgraph, isShareable }); | ||
addSubgraphField({ field, type: subgraphType, subgraph, isShareable, originalDirectiveNames }); | ||
} | ||
@@ -479,3 +489,3 @@ } else { | ||
const { type: subgraphType, subgraph } = subgraphsInfo.get(joinFieldArgs.graph)!; | ||
addSubgraphField({ field, type: subgraphType, subgraph, isShareable, joinFieldArgs }); | ||
addSubgraphField({ field, type: subgraphType, subgraph, isShareable, joinFieldArgs, originalDirectiveNames }); | ||
} | ||
@@ -487,4 +497,47 @@ } | ||
/** | ||
* Builds a map of original name to new name for Apollo feature directives. This is | ||
* used to handle cases where a directive is renamed via an import statement. For | ||
* example, importing a directive with a custom name like | ||
* ```graphql | ||
* @link(url: "https://specs.apollo.dev/cost/v0.1", import: [{ name: "@cost", as: "@renamedCost" }]) | ||
* ``` | ||
* results in a map entry of `cost -> renamedCost` with the `@` prefix removed. | ||
* | ||
* If the directive is imported under its default name, that also results in an entry. So, | ||
* ```graphql | ||
* @link(url: "https://specs.apollo.dev/cost/v0.1", import: ["@cost"]) | ||
* ``` | ||
* results in a map entry of `cost -> cost`. This duals as a way to check if a directive | ||
* is included in the supergraph schema. | ||
* | ||
* **Important:** This map does _not_ include directives imported from identities other | ||
* than `specs.apollo.dev`. This helps us avoid extracting directives to subgraphs | ||
* when a custom directive's name conflicts with that of a default one. | ||
*/ | ||
function getApolloDirectiveNames(supergraph: Schema): Record<string, string> { | ||
const originalDirectiveNames: Record<string, string> = {}; | ||
for (const linkDirective of supergraph.schemaDefinition.appliedDirectivesOf("link")) { | ||
if (linkDirective.arguments().url && linkDirective.arguments().import) { | ||
const url = FeatureUrl.maybeParse(linkDirective.arguments().url); | ||
if (!url?.identity.includes("specs.apollo.dev")) { | ||
continue; | ||
} | ||
for (const importedDirective of linkDirective.arguments().import) { | ||
if (importedDirective.name && importedDirective.as) { | ||
originalDirectiveNames[importedDirective.name.replace('@', '')] = importedDirective.as.replace('@', ''); | ||
} else if (typeof importedDirective === 'string') { | ||
originalDirectiveNames[importedDirective.replace('@', '')] = importedDirective.replace('@', ''); | ||
} | ||
} | ||
} | ||
} | ||
return originalDirectiveNames; | ||
} | ||
function extractInputObjContent(args: ExtractArguments, info: TypeInfo<InputObjectType>[]) { | ||
const fieldDirective = args.joinSpec.fieldDirective(args.supergraph); | ||
const originalDirectiveNames = args.originalDirectiveNames; | ||
@@ -497,3 +550,3 @@ for (const { type, subgraphsInfo } of info) { | ||
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) { | ||
addSubgraphInputField({ field, type: subgraphType, subgraph }); | ||
addSubgraphInputField({ field, type: subgraphType, subgraph, originalDirectiveNames }); | ||
} | ||
@@ -510,3 +563,3 @@ } else { | ||
const { type: subgraphType, subgraph } = subgraphsInfo.get(args.graph)!; | ||
addSubgraphInputField({ field, type: subgraphType, subgraph, joinFieldArgs: args}); | ||
addSubgraphInputField({ field, type: subgraphType, subgraph, joinFieldArgs: args, originalDirectiveNames }); | ||
} | ||
@@ -521,4 +574,9 @@ } | ||
const enumValueDirective = args.joinSpec.enumValueDirective(args.supergraph); | ||
const originalDirectiveNames = args.originalDirectiveNames; | ||
for (const { type, subgraphsInfo } of info) { | ||
for (const { type: subgraphType, subgraph } of subgraphsInfo.values()) { | ||
propagateDemandControlDirectives(type, subgraphType, subgraph, originalDirectiveNames); | ||
} | ||
for (const value of type.values) { | ||
@@ -636,2 +694,20 @@ const enumValueApplications = enumValueDirective ? value.appliedDirectivesOf(enumValueDirective) : []; | ||
function propagateDemandControlDirectives(source: SchemaElement<any, any>, dest: SchemaElement<any, any>, subgraph: Subgraph, originalDirectiveNames?: Record<string, string>) { | ||
const costDirectiveName = originalDirectiveNames?.[FederationDirectiveName.COST]; | ||
if (costDirectiveName) { | ||
const costDirective = source.appliedDirectivesOf(costDirectiveName).pop(); | ||
if (costDirective) { | ||
dest.applyDirective(subgraph.metadata().costDirective().name, costDirective.arguments()); | ||
} | ||
} | ||
const listSizeDirectiveName = originalDirectiveNames?.[FederationDirectiveName.LIST_SIZE]; | ||
if (listSizeDirectiveName) { | ||
const listSizeDirective = source.appliedDirectivesOf(listSizeDirectiveName).pop(); | ||
if (listSizeDirective) { | ||
dest.applyDirective(subgraph.metadata().listSizeDirective().name, listSizeDirective.arguments()); | ||
} | ||
} | ||
} | ||
function errorToString(e: any,): string { | ||
@@ -648,2 +724,3 @@ const causes = errorCauses(e); | ||
joinFieldArgs, | ||
originalDirectiveNames, | ||
}: { | ||
@@ -655,2 +732,3 @@ field: FieldDefinition<ObjectType | InterfaceType>, | ||
joinFieldArgs?: JoinFieldDirectiveArguments, | ||
originalDirectiveNames?: Record<string, string>, | ||
}): FieldDefinition<ObjectType | InterfaceType> { | ||
@@ -663,3 +741,4 @@ const copiedFieldType = joinFieldArgs?.type | ||
for (const arg of field.arguments()) { | ||
subgraphField.addArgument(arg.name, copyType(arg.type!, subgraph.schema, subgraph.name), arg.defaultValue); | ||
const argDef = subgraphField.addArgument(arg.name, copyType(arg.type!, subgraph.schema, subgraph.name), arg.defaultValue); | ||
propagateDemandControlDirectives(arg, argDef, subgraph, originalDirectiveNames) | ||
} | ||
@@ -709,2 +788,5 @@ if (joinFieldArgs?.requires) { | ||
} | ||
propagateDemandControlDirectives(field, subgraphField, subgraph, originalDirectiveNames); | ||
return subgraphField; | ||
@@ -718,2 +800,3 @@ } | ||
joinFieldArgs, | ||
originalDirectiveNames, | ||
}: { | ||
@@ -724,2 +807,3 @@ field: InputFieldDefinition, | ||
joinFieldArgs?: JoinFieldDirectiveArguments, | ||
originalDirectiveNames?: Record<string, string> | ||
}): InputFieldDefinition { | ||
@@ -732,2 +816,5 @@ const copiedType = joinFieldArgs?.type | ||
inputField.defaultValue = field.defaultValue | ||
propagateDemandControlDirectives(field, inputField, subgraph, originalDirectiveNames); | ||
return inputField; | ||
@@ -734,0 +821,0 @@ } |
@@ -28,1 +28,2 @@ export * from './definitions'; | ||
export * from './specs/connectSpec'; | ||
export * from './specs/costSpec'; |
@@ -14,2 +14,3 @@ import { | ||
FieldDefinition, | ||
InterfaceType, | ||
isCompositeType, | ||
@@ -234,3 +235,25 @@ isInterfaceType, | ||
const subgraphsUsingInterfaceObject = []; | ||
// build a data structure to help us do computation only once | ||
const objectTypeMap = new Map<string, Map<string, [ObjectType | InterfaceType, FederationMetadata]>>(); | ||
for (const subgraph of inputs.values()) { | ||
for (const t of subgraph.schema.objectTypes()) { | ||
let entry = objectTypeMap.get(t.name); | ||
if (!entry) { | ||
entry = new Map(); | ||
objectTypeMap.set(t.name, entry); | ||
} | ||
entry.set(subgraph.name, [t, subgraph.metadata()]); | ||
} | ||
for (const t of subgraph.schema.interfaceTypes()) { | ||
let entry = objectTypeMap.get(t.name); | ||
if (!entry) { | ||
entry = new Map(); | ||
objectTypeMap.set(t.name, entry); | ||
} | ||
entry.set(subgraph.name, [t, subgraph.metadata()]); | ||
} | ||
} | ||
for (const subgraph of inputs.values()) { | ||
if (subgraph.isFed2Subgraph()) { | ||
@@ -242,4 +265,3 @@ subgraphs.add(subgraph); | ||
} else { | ||
const otherSubgraphs = inputs.values().filter((s) => s.name !== subgraph.name); | ||
const res = new SchemaUpgrader(subgraph, otherSubgraphs).upgrade(); | ||
const res = new SchemaUpgrader(subgraph, inputs.values(), objectTypeMap).upgrade(); | ||
if (res.errors) { | ||
@@ -297,12 +319,2 @@ errors = errors.concat(res.errors); | ||
function resolvesField(subgraph: Subgraph, field: FieldDefinition<ObjectType>): boolean { | ||
const metadata = subgraph.metadata(); | ||
const t = subgraph.schema.type(field.parent.name); | ||
if (!t || !isObjectType(t)) { | ||
return false; | ||
} | ||
const f = t.field(field.name); | ||
return !!f && (!metadata.isFieldExternal(f) || metadata.isFieldPartiallyExternal(f)); | ||
} | ||
function getField(schema: Schema, typeName: string, fieldName: string): FieldDefinition<CompositeType> | undefined { | ||
@@ -320,3 +332,3 @@ const type = schema.type(typeName); | ||
constructor(private readonly originalSubgraph: Subgraph, private readonly otherSubgraphs: Subgraph[]) { | ||
constructor(private readonly originalSubgraph: Subgraph, private readonly allSubgraphs: readonly Subgraph[], private readonly objectTypeMap: Map<string, Map<string, [ObjectType | InterfaceType, FederationMetadata]>>) { | ||
// Note that as we clone the original schema, the 'sourceAST' values in the elements of the new schema will be those of the original schema | ||
@@ -388,4 +400,5 @@ // and those won't be updated as we modify the schema to make it fed2-enabled. This is _important_ for us here as this is what ensures that | ||
const extensionAST = firstOf<Extension<any>>(type.extensions().values())?.sourceAST; | ||
for (const subgraph of this.otherSubgraphs) { | ||
const otherType = subgraph.schema.type(type.name); | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name)!.entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
for (let i = 0; i < typeInOtherSubgraphs.length; i += 1) { | ||
const otherType = typeInOtherSubgraphs[i][1][0]; | ||
if (otherType && otherType.hasNonExtensionElements()) { | ||
@@ -598,9 +611,8 @@ return; | ||
// not good enough). | ||
for (const other of this.otherSubgraphs) { | ||
const typeInOther = other.schema.type(type.name); | ||
if (!typeInOther) { | ||
continue; | ||
} | ||
assert(isCompositeType(typeInOther), () => `Type ${type} is of kind ${type.kind} in ${this.subgraph.name} but ${typeInOther.kind} in ${other.name}`); | ||
const keysInOther = typeInOther.appliedDirectivesOf(other.metadata().keyDirective()); | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name)!.entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
for (const [otherSubgraphName, v] of typeInOtherSubgraphs) { | ||
const [typeInOther, metadata] = v; | ||
assert(isCompositeType(typeInOther), () => `Type ${type} is of kind ${type.kind} in ${this.subgraph.name} but ${typeInOther.kind} in ${otherSubgraphName}`); | ||
const keysInOther = typeInOther.appliedDirectivesOf(metadata.keyDirective()); | ||
if (keysInOther.length === 0) { | ||
@@ -712,3 +724,6 @@ continue; | ||
for (const type of this.schema.objectTypes()) { | ||
if (type.hasAppliedDirective(keyDirective) || type.isRootType()) { | ||
if(type.isSubscriptionRootType()) { | ||
continue; | ||
} | ||
if (type.hasAppliedDirective(keyDirective) || (type.isRootType())) { | ||
for (const field of type.fields()) { | ||
@@ -721,13 +736,22 @@ // To know if the field is a "key" field which doesn't need shareable, we rely on whether the field is shareable in the original | ||
} | ||
const otherResolvingSubgraphs = this.otherSubgraphs.filter((s) => resolvesField(s, field)); | ||
if (otherResolvingSubgraphs.length > 0 && !field.hasAppliedDirective(shareableDirective)) { | ||
const entries = Array.from(this.objectTypeMap.get(type.name)!.entries()); | ||
const typeInOtherSubgraphs = entries.filter(([subgraphName, v]) => { | ||
if (subgraphName === this.subgraph.name) { | ||
return false; | ||
} | ||
const f = v[0].field(field.name); | ||
return !!f && (!v[1].isFieldExternal(f) || v[1].isFieldPartiallyExternal(f)); | ||
}); | ||
if (typeInOtherSubgraphs.length > 0 && !field.hasAppliedDirective(shareableDirective)) { | ||
field.applyDirective(shareableDirective); | ||
this.addChange(new ShareableFieldAddition(field.coordinate, otherResolvingSubgraphs.map((s) => s.name))); | ||
this.addChange(new ShareableFieldAddition(field.coordinate, typeInOtherSubgraphs.map(([s]) => s))); | ||
} | ||
} | ||
} else { | ||
const otherDeclaringSubgraphs = this.otherSubgraphs.filter((s) => s.schema.type(type.name)); | ||
if (otherDeclaringSubgraphs.length > 0 && !type.hasAppliedDirective(shareableDirective)) { | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name)!.entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
if (typeInOtherSubgraphs.length > 0 && !type.hasAppliedDirective(shareableDirective)) { | ||
type.applyDirective(shareableDirective); | ||
this.addChange(new ShareableTypeAddition(type.coordinate, otherDeclaringSubgraphs.map((s) => s.name))); | ||
this.addChange(new ShareableTypeAddition(type.coordinate, typeInOtherSubgraphs.map(([s]) => s))); | ||
} | ||
@@ -751,4 +775,4 @@ } | ||
if (this.external(element)) { | ||
const tagIsUsedInOtherDefinition = this.otherSubgraphs | ||
.map((s) => getField(s.schema, element.parent.name, element.name)) | ||
const tagIsUsedInOtherDefinition = this.allSubgraphs | ||
.map((s) => s.name === this.originalSubgraph.name ? undefined : getField(s.schema, element.parent.name, element.name)) | ||
.filter((f) => !(f && f.hasAppliedDirective('external'))) | ||
@@ -755,0 +779,0 @@ .some((f) => f && f.appliedDirectivesOf('tag').some((d) => valueEquals(application.arguments(), d.arguments()))); |
@@ -11,3 +11,3 @@ import {DirectiveLocation, GraphQLError} from 'graphql'; | ||
import { registerKnownFeature } from '../knownCoreFeatures'; | ||
import { createDirectiveSpecification } from '../directiveAndTypeSpecification'; | ||
import { createDirectiveSpecification, createScalarTypeSpecification } from '../directiveAndTypeSpecification'; | ||
@@ -45,4 +45,4 @@ export const connectIdentity = 'https://specs.apollo.dev/connect'; | ||
this.registerType({ name: URL_PATH_TEMPLATE, checkOrAdd: () => [] }); | ||
this.registerType({ name: JSON_SELECTION, checkOrAdd: () => [] }); | ||
this.registerType(createScalarTypeSpecification({ name: URL_PATH_TEMPLATE })); | ||
this.registerType(createScalarTypeSpecification({ name: JSON_SELECTION })); | ||
this.registerType({ name: CONNECT_HTTP, checkOrAdd: () => [] }); | ||
@@ -147,40 +147,5 @@ this.registerType({ name: SOURCE_HTTP, checkOrAdd: () => [] }); | ||
export type SourceDirectiveArgs = { | ||
name: string; | ||
http: SourceDirectiveHTTP; | ||
}; | ||
export type SourceDirectiveHTTP = { | ||
baseURL: string; | ||
headers?: HTTPHeaderMapping[]; | ||
}; | ||
type HTTPHeaderMapping = { | ||
name: string; | ||
as?: string; | ||
value?: string; | ||
}; | ||
type URLPathTemplate = string; | ||
type JSONSelection = string; | ||
export type ConnectDirectiveArgs = { | ||
source: string; | ||
http: ConnectDirectiveHTTP; | ||
selection?: JSONSelection; | ||
}; | ||
export type ConnectDirectiveHTTP = { | ||
GET?: URLPathTemplate; | ||
POST?: URLPathTemplate; | ||
PUT?: URLPathTemplate; | ||
PATCH?: URLPathTemplate; | ||
DELETE?: URLPathTemplate; | ||
body?: JSONSelection; | ||
headers?: HTTPHeaderMapping[]; | ||
}; | ||
export const CONNECT_VERSIONS = new FeatureDefinitions<ConnectSpecDefinition>(connectIdentity) | ||
.add(new ConnectSpecDefinition(new FeatureVersion(0, 1), new FeatureVersion(2, 9))); | ||
.add(new ConnectSpecDefinition(new FeatureVersion(0, 1), new FeatureVersion(2, 10))); | ||
registerKnownFeature(CONNECT_VERSIONS); |
@@ -550,2 +550,23 @@ import { ASTNode, DirectiveLocation, GraphQLError, StringValueNode } from "graphql"; | ||
applyFeatureAsLink(schema: Schema, feature: FeatureDefinition, purpose?: CorePurpose, imports?: CoreImport[]): GraphQLError[] { | ||
const existing = schema.schemaDefinition.appliedDirectivesOf(linkDirectiveDefaultName).find((link) => link.arguments().url === feature.toString()); | ||
if (existing) { | ||
existing.remove(); | ||
} | ||
const coreDirective = this.coreDirective(schema); | ||
const args: LinkDirectiveArgs = { | ||
url: feature.toString(), | ||
import: (existing?.arguments().import ?? []).concat(imports?.map((i) => i.as ? { name: `@${i.name}`, as: `@${i.as}` } : `@${i.name}`)), | ||
feature: undefined, | ||
}; | ||
if (this.supportPurposes() && purpose) { | ||
args.for = purpose; | ||
} | ||
schema.schemaDefinition.applyDirective(coreDirective, args); | ||
return feature.addElementsToSchema(schema); | ||
} | ||
extractFeatureUrl(args: CoreOrLinkDirectiveArgs): FeatureUrl { | ||
@@ -601,3 +622,3 @@ return FeatureUrl.parse(args[this.urlArgName()]!); | ||
// if the minimum version is not present, assume that we won't look for an older version | ||
const def = this._definitions.find(def => def.minimumFederationVersion ? fedVersion >= def.minimumFederationVersion : true); | ||
const def = this._definitions.find(def => def.minimumFederationVersion ? fedVersion.gte(def.minimumFederationVersion) : true); | ||
assert(def, `No compatible definition exists for federation version ${fedVersion}`); | ||
@@ -654,3 +675,3 @@ | ||
for (const version of versions) { | ||
if (!max || version > max) { | ||
if (!max || version.gt(max)) { | ||
max = version; | ||
@@ -657,0 +678,0 @@ } |
@@ -22,2 +22,3 @@ import { | ||
import { CONTEXT_VERSIONS } from './contextSpec'; | ||
import { COST_VERSIONS } from "./costSpec"; | ||
@@ -48,2 +49,4 @@ export const federationIdentity = 'https://specs.apollo.dev/federation'; | ||
FROM_CONTEXT = 'fromContext', | ||
COST = 'cost', | ||
LIST_SIZE = 'listSize', | ||
} | ||
@@ -133,3 +136,3 @@ | ||
if (version >= (new FeatureVersion(2, 7))) { | ||
if (version.gte(new FeatureVersion(2, 7))) { | ||
this.registerDirective(createDirectiveSpecification({ | ||
@@ -180,2 +183,6 @@ name: FederationDirectiveName.OVERRIDE, | ||
} | ||
if (version.gte(new FeatureVersion(2, 9))) { | ||
this.registerSubFeature(COST_VERSIONS.find(new FeatureVersion(0, 1))!); | ||
} | ||
} | ||
@@ -193,4 +200,6 @@ } | ||
.add(new FederationSpecDefinition(new FeatureVersion(2, 7))) | ||
.add(new FederationSpecDefinition(new FeatureVersion(2, 8))); | ||
.add(new FederationSpecDefinition(new FeatureVersion(2, 8))) | ||
.add(new FederationSpecDefinition(new FeatureVersion(2, 9))) | ||
.add(new FederationSpecDefinition(new FeatureVersion(2, 10))); | ||
registerKnownFeature(FEDERATION_VERSIONS); |
@@ -43,2 +43,4 @@ import { DocumentNode, GraphQLError } from "graphql"; | ||
'https://specs.apollo.dev/context/v0.1', | ||
'https://specs.apollo.dev/cost/v0.1', | ||
'https://specs.apollo.dev/connect/v0.1', | ||
]); | ||
@@ -45,0 +47,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 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 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
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
2193158
178
34767