@apollo/federation-internals
Advanced tools
Comparing version 2.8.4 to 2.9.0-beta.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 @@ } |
@@ -8,2 +8,3 @@ import { CompositeType, CoreFeature, Directive, DirectiveDefinition, FieldDefinition, InputFieldDefinition, InterfaceType, NamedType, ObjectType, ScalarType, Schema, SchemaBlueprint, SchemaConfig, SchemaElement, UnionType } from "./definitions"; | ||
import { SourceAPIDirectiveArgs, SourceFieldDirectiveArgs, SourceTypeDirectiveArgs } from "./specs/sourceSpec"; | ||
import { CostDirectiveArguments, ListSizeDirectiveArguments } from "./specs/costSpec"; | ||
export declare const FEDERATION_RESERVED_SUBGRAPH_NAME = "_"; | ||
@@ -88,2 +89,4 @@ export declare const FEDERATION_UNNAMED_SUBGRAPH_NAME = "<unnamed>"; | ||
}>; | ||
costDirective(): Post20FederationDirectiveDefinition<CostDirectiveArguments>; | ||
listSizeDirective(): Post20FederationDirectiveDefinition<ListSizeDirectiveArguments>; | ||
allFederationDirectives(): DirectiveDefinition[]; | ||
@@ -124,4 +127,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\", \"@sourceAPI\", \"@sourceType\", \"@sourceField\", \"@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.9\", import: [\"@key\", \"@requires\", \"@provides\", \"@external\", \"@tag\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@composeDirective\", \"@interfaceObject\", \"@authenticated\", \"@requiresScopes\", \"@policy\", \"@sourceAPI\", \"@sourceType\", \"@sourceField\", \"@context\", \"@fromContext\", \"@cost\", \"@listSize\"])"; | ||
export declare const FEDERATION2_LINK_WITH_AUTO_EXPANDED_IMPORTS = "@link(url: \"https://specs.apollo.dev/federation/v2.9\", 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\"])"; | ||
@@ -128,0 +131,0 @@ export declare function asFed2SubgraphDocument(document: DocumentNode, options?: { |
@@ -28,2 +28,3 @@ export * from './definitions'; | ||
export * from './specs/sourceSpec'; | ||
export * from './specs/costSpec'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -46,2 +46,3 @@ "use strict"; | ||
__exportStar(require("./specs/sourceSpec"), exports); | ||
__exportStar(require("./specs/costSpec"), exports); | ||
//# sourceMappingURL=index.js.map |
import { ArgumentNode, DocumentNode, FieldNode, FragmentDefinitionNode, OperationDefinitionNode, SelectionNode, SelectionSetNode } from "graphql"; | ||
import { Directive, DirectiveTargetElement, FieldDefinition, Schema, SchemaRootKind, VariableCollector, VariableDefinitions, CompositeType, DeferDirectiveArgs, Variable, Type, Variables, NamedType } from "./definitions"; | ||
import { MultiMap, SetMultiMap } from "./utils"; | ||
export declare const DEFAULT_MIN_USAGES_TO_OPTIMIZE = 2; | ||
declare abstract class AbstractOperationElement<T extends AbstractOperationElement<T>> extends DirectiveTargetElement<T> { | ||
@@ -107,4 +108,5 @@ private attachements?; | ||
private withUpdatedSelectionSet; | ||
private collectUndefinedVariablesFromFragments; | ||
private withUpdatedSelectionSetAndFragments; | ||
optimize(fragments?: NamedFragments, minUsagesToOptimize?: number): Operation; | ||
optimize(fragments?: NamedFragments, minUsagesToOptimize?: number, allAvailableVariables?: VariableDefinitions): Operation; | ||
generateQueryFragments(): Operation; | ||
@@ -111,0 +113,0 @@ expandAllFragments(): Operation; |
@@ -83,2 +83,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; | ||
@@ -85,0 +86,0 @@ urlArgName(): 'feature' | 'url'; |
@@ -396,2 +396,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) { | ||
@@ -398,0 +416,0 @@ return FeatureUrl.parse(args[this.urlArgName()]); |
@@ -26,3 +26,5 @@ import { FeatureDefinition, FeatureDefinitions, FeatureVersion } from "./coreSpec"; | ||
CONTEXT = "context", | ||
FROM_CONTEXT = "fromContext" | ||
FROM_CONTEXT = "fromContext", | ||
COST = "cost", | ||
LIST_SIZE = "listSize" | ||
} | ||
@@ -29,0 +31,0 @@ export declare const FEDERATION1_TYPES: import("../directiveAndTypeSpecification").TypeSpecification[]; |
@@ -18,2 +18,3 @@ "use strict"; | ||
const contextSpec_1 = require("./contextSpec"); | ||
const costSpec_1 = require("./costSpec"); | ||
exports.federationIdentity = 'https://specs.apollo.dev/federation'; | ||
@@ -46,2 +47,4 @@ var FederationTypeName; | ||
FederationDirectiveName["FROM_CONTEXT"] = "fromContext"; | ||
FederationDirectiveName["COST"] = "cost"; | ||
FederationDirectiveName["LIST_SIZE"] = "listSize"; | ||
})(FederationDirectiveName || (exports.FederationDirectiveName = FederationDirectiveName = {})); | ||
@@ -156,2 +159,5 @@ const fieldSetTypeSpec = (0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name: FederationTypeName.FIELD_SET }); | ||
} | ||
if (version.gte(new coreSpec_1.FeatureVersion(2, 9))) { | ||
this.registerSubFeature(costSpec_1.COST_VERSIONS.find(new coreSpec_1.FeatureVersion(0, 1))); | ||
} | ||
} | ||
@@ -169,4 +175,5 @@ } | ||
.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))); | ||
(0, knownCoreFeatures_1.registerKnownFeature)(exports.FEDERATION_VERSIONS); | ||
//# sourceMappingURL=federationSpec.js.map |
@@ -42,2 +42,3 @@ "use strict"; | ||
'https://specs.apollo.dev/context/v0.1', | ||
'https://specs.apollo.dev/cost/v0.1', | ||
]); | ||
@@ -44,0 +45,0 @@ const coreVersionZeroDotOneUrl = coreSpec_1.FeatureUrl.parse('https://specs.apollo.dev/core/v0.1'); |
{ | ||
"name": "@apollo/federation-internals", | ||
"version": "2.8.4", | ||
"version": "2.9.0-beta.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/sourceSpec'; | ||
export * from './specs/costSpec'; |
@@ -555,2 +555,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 { | ||
@@ -557,0 +578,0 @@ return FeatureUrl.parse(args[this.urlArgName()]!); |
@@ -23,2 +23,3 @@ import { | ||
import { CONTEXT_VERSIONS } from './contextSpec'; | ||
import { COST_VERSIONS } from "./costSpec"; | ||
@@ -52,2 +53,4 @@ export const federationIdentity = 'https://specs.apollo.dev/federation'; | ||
FROM_CONTEXT = 'fromContext', | ||
COST = 'cost', | ||
LIST_SIZE = 'listSize', | ||
} | ||
@@ -187,2 +190,6 @@ | ||
} | ||
if (version.gte(new FeatureVersion(2, 9))) { | ||
this.registerSubFeature(COST_VERSIONS.find(new FeatureVersion(0, 1))!); | ||
} | ||
} | ||
@@ -200,4 +207,5 @@ } | ||
.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))); | ||
registerKnownFeature(FEDERATION_VERSIONS); |
@@ -43,2 +43,3 @@ import { DocumentNode, GraphQLError } from "graphql"; | ||
'https://specs.apollo.dev/context/v0.1', | ||
'https://specs.apollo.dev/cost/v0.1', | ||
]); | ||
@@ -45,0 +46,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 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 too big to display
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
2262167
178
35821
2