Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@apollo/federation-internals

Package Overview
Dependencies
Maintainers
1
Versions
131
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@apollo/federation-internals - npm Package Compare versions

Comparing version 2.4.0-alpha.1 to 2.4.0

19

CHANGELOG.md
# CHANGELOG for `@apollo/federation-internals`
## 2.4.0
### Patch Changes
- Refactor the internal implementation of selection sets used by the query planner to decrease the code complexity and ([#2387](https://github.com/apollographql/federation/pull/2387))
improve query plan generation performance in many cases.
- Revert #2293. Removing URL import causes a problem when running under deno. ([#2451](https://github.com/apollographql/federation/pull/2451))
- Use globally available URL object instead of node builtin "url" module ([#2293](https://github.com/apollographql/federation/pull/2293))
- Optimises query plan generation for parts of queries that can statically be known to not cross across subgraphs ([#2449](https://github.com/apollographql/federation/pull/2449))
## 2.4.0-alpha.1

@@ -19,2 +34,6 @@ ### Patch Changes

## 2.3.4
### Patch Changes
- Use globally available URL object instead of node builtin "url" module ([#2293](https://github.com/apollographql/federation/pull/2293))

@@ -21,0 +40,0 @@

30

dist/definitions.d.ts

@@ -70,5 +70,6 @@ import { ConstArgumentNode, ASTNode, DirectiveLocation, ConstDirectiveNode, DocumentNode, GraphQLError, GraphQLSchema, Kind, TypeNode, VariableDefinitionNode, VariableNode, DirectiveDefinitionNode, DirectiveNode } from "graphql";

private readonly _schema;
private _appliedDirectives;
constructor(_schema: Schema);
readonly appliedDirectives: Directive<T>[];
constructor(_schema: Schema, directives?: readonly Directive<any>[]);
schema(): Schema;
private attachDirective;
appliedDirectivesOf<TApplicationArgs extends {

@@ -79,12 +80,6 @@ [key: string]: any;

}>(nameOrDefinition: string | DirectiveDefinition<TApplicationArgs>): Directive<T, TApplicationArgs>[];
get appliedDirectives(): readonly Directive<T>[];
hasAppliedDirective(nameOrDefinition: string | DirectiveDefinition): boolean;
applyDirective<TApplicationArgs extends {
[key: string]: any;
} = {
[key: string]: any;
}>(defOrDirective: Directive<T, TApplicationArgs> | DirectiveDefinition<TApplicationArgs>, args?: TApplicationArgs): Directive<T, TApplicationArgs>;
appliedDirectivesToDirectiveNodes(): ConstDirectiveNode[] | undefined;
appliedDirectivesToString(): string;
variablesInAppliedDirectives(): Variables;
collectVariablesInAppliedDirectives(collector: VariableCollector): void;
}

@@ -601,3 +596,3 @@ export declare function sourceASTs<TNode extends ASTNode = ASTNode>(...elts: ({

private _extension?;
constructor(name: string, _args: TArgs);
constructor(name: string, _args?: TArgs);
schema(): Schema;

@@ -630,8 +625,13 @@ get definition(): DirectiveDefinition | undefined;

export type Variables = readonly Variable[];
export declare function mergeVariables(v1s: Variables, v2s: Variables): Variables;
export declare function containsVariable(variables: Variables, toCheck: Variable): boolean;
export declare class VariableCollector {
private readonly _variables;
add(variable: Variable): void;
addAll(variables: Variables): void;
collectInArguments(args: {
[key: string]: any;
}): void;
variables(): Variable[];
toString(): string;
}
export declare function isVariable(v: any): v is Variable;
export declare function variablesInArguments(args: {
[key: string]: any;
}): Variables;
export declare class VariableDefinition extends DirectiveTargetElement<VariableDefinition> {

@@ -638,0 +638,0 @@ readonly variable: Variable;

@@ -35,3 +35,3 @@ "use strict";

for (const selection of selectionSet.selections()) {
const appliedDirectives = selection.element().appliedDirectives;
const appliedDirectives = selection.element.appliedDirectives;
if (appliedDirectives.length > 0) {

@@ -41,3 +41,3 @@ onError(error_1.ERROR_CATEGORIES.DIRECTIVE_IN_FIELDS_ARG.get(directiveName).err(`cannot have directive applications in the @${directiveName}(fields:) argument but found ${appliedDirectives.join(', ')}.`));

if (selection.kind === 'FieldSelection') {
const field = selection.element().definition;
const field = selection.element.definition;
const isExternal = metadata.isFieldExternal(field);

@@ -1256,8 +1256,11 @@ if (!allowFieldsWithArguments && field.hasArguments()) {

const parent = provides.parent;
collectTargetFields({
parentType: (0, definitions_1.baseType)(parent.type),
directive: provides,
includeInterfaceFieldsImplementations: true,
validate: false,
}).forEach((f) => this.providedFields.add(f.coordinate));
const parentType = (0, definitions_1.baseType)(parent.type);
if ((0, definitions_1.isCompositeType)(parentType)) {
collectTargetFields({
parentType,
directive: provides,
includeInterfaceFieldsImplementations: true,
validate: false,
}).forEach((f) => this.providedFields.add(f.coordinate));
}
}

@@ -1285,3 +1288,3 @@ }

for (const selection of selectionSet.selections()) {
if (selection.kind === 'FieldSelection' && this.isExternal(selection.element().definition)) {
if (selection.kind === 'FieldSelection' && this.isExternal(selection.element.definition)) {
return true;

@@ -1367,3 +1370,3 @@ }

if (s.kind === 'FieldSelection') {
if (isExternalOrHasExternalImplementations(s.field.definition)) {
if (isExternalOrHasExternalImplementations(s.element.definition)) {
return false;

@@ -1379,8 +1382,6 @@ }

function withoutNonExternalLeafFields(selectionSet) {
const newSelectionSet = new operations_1.SelectionSet(selectionSet.parentType);
for (const selection of selectionSet.selections()) {
return selectionSet.lazyMap((selection) => {
if (selection.kind === 'FieldSelection') {
if (isExternalOrHasExternalImplementations(selection.field.definition)) {
newSelectionSet.add(selection);
continue;
if (isExternalOrHasExternalImplementations(selection.element.definition)) {
return selection;
}

@@ -1391,8 +1392,8 @@ }

if (!updated.isEmpty()) {
newSelectionSet.add((0, operations_1.selectionOfElement)(selection.element(), updated));
return selection.withUpdatedSelectionSet(updated);
}
}
}
return newSelectionSet;
return undefined;
});
}
//# sourceMappingURL=federation.js.map

@@ -1,10 +0,13 @@

import { DocumentNode, FieldNode, FragmentDefinitionNode, SelectionNode, SelectionSetNode } from "graphql";
import { Directive, DirectiveTargetElement, FieldDefinition, InterfaceType, ObjectType, Schema, SchemaRootKind, Variables, VariableDefinitions, CompositeType, DeferDirectiveArgs, Variable, Type } from "./definitions";
import { ArgumentNode, DocumentNode, FieldNode, FragmentDefinitionNode, SelectionNode, SelectionSetNode } from "graphql";
import { Directive, DirectiveTargetElement, FieldDefinition, InterfaceType, ObjectType, Schema, SchemaRootKind, VariableCollector, VariableDefinitions, CompositeType, DeferDirectiveArgs, Variable, Type, Variables } from "./definitions";
import { SetMultiMap } from "./utils";
declare abstract class AbstractOperationElement<T extends AbstractOperationElement<T>> extends DirectiveTargetElement<T> {
private readonly variablesInElement;
private attachements?;
constructor(schema: Schema, variablesInElement: Variables);
variables(): Variables;
abstract updateForAddingTo(selection: SelectionSet): T;
constructor(schema: Schema, directives?: readonly Directive<any>[]);
collectVariables(collector: VariableCollector): void;
abstract key(): string;
abstract asPathElement(): string | undefined;
abstract rebaseOn(parentType: CompositeType): T;
abstract withUpdatedDirectives(newDirectives: readonly Directive<any>[]): T;
protected abstract collectVariablesInElement(collector: VariableCollector): void;
addAttachement(key: string, value: string): void;

@@ -20,16 +23,22 @@ getAttachement(key: string): string | undefined;

readonly definition: FieldDefinition<CompositeType>;
readonly args: TArgs;
readonly variableDefinitions: VariableDefinitions;
private readonly args?;
readonly alias?: string | undefined;
readonly kind: "Field";
constructor(definition: FieldDefinition<CompositeType>, args?: TArgs, variableDefinitions?: VariableDefinitions, alias?: string | undefined);
constructor(definition: FieldDefinition<CompositeType>, args?: TArgs | undefined, directives?: readonly Directive<any>[], alias?: string | undefined);
protected collectVariablesInElement(collector: VariableCollector): void;
get name(): string;
argumentValue(name: string): any;
responseName(): string;
key(): string;
asPathElement(): string;
get parentType(): CompositeType;
isLeafField(): boolean;
withUpdatedDefinition(newDefinition: FieldDefinition<any>): Field<TArgs>;
withUpdatedAlias(newAlias: string | undefined): Field<TArgs>;
withUpdatedDirectives(newDirectives: readonly Directive<any>[]): Field<TArgs>;
argumentsToNodes(): ArgumentNode[] | undefined;
appliesTo(type: ObjectType | InterfaceType): boolean;
selects(definition: FieldDefinition<any>, assumeValid?: boolean): boolean;
validate(): void;
updateForAddingTo(selectionSet: SelectionSet): Field<TArgs>;
selects(definition: FieldDefinition<any>, assumeValid?: boolean, variableDefinitions?: VariableDefinitions): boolean;
validate(variableDefinitions: VariableDefinitions): void;
rebaseOn(parentType: CompositeType): Field<TArgs>;
private canRebaseOn;

@@ -47,9 +56,14 @@ typeIfAddedTo(parentType: CompositeType): Type | undefined;

readonly typeCondition?: CompositeType;
constructor(sourceType: CompositeType, typeCondition?: string | CompositeType);
private computedKey;
constructor(sourceType: CompositeType, typeCondition?: string | CompositeType, directives?: readonly Directive<any>[]);
protected collectVariablesInElement(_: VariableCollector): void;
get parentType(): CompositeType;
key(): string;
castedType(): CompositeType;
asPathElement(): string | undefined;
withUpdatedSourceType(newSourceType: CompositeType): FragmentElement;
withUpdatedCondition(newCondition: CompositeType | undefined): FragmentElement;
withUpdatedTypes(newSourceType: CompositeType, newCondition: CompositeType | undefined): FragmentElement;
updateForAddingTo(selectionSet: SelectionSet): FragmentElement;
withUpdatedDirectives(newDirectives: Directive<OperationElement>[]): FragmentElement;
rebaseOn(parentType: CompositeType): FragmentElement;
private canRebaseOn;

@@ -84,2 +98,3 @@ castedTypeIfAddedTo(parentType: CompositeType): CompositeType | undefined;

expandAllFragments(): Operation;
trimUnsatisfiableBranches(): Operation;
withoutDefer(labelsToRemove?: Set<string>): Operation;

@@ -95,10 +110,10 @@ withNormalizedDefer(): {

}
export declare function selectionSetOf(parentType: CompositeType, selection: Selection): SelectionSet;
export declare class NamedFragmentDefinition extends DirectiveTargetElement<NamedFragmentDefinition> {
readonly name: string;
readonly typeCondition: CompositeType;
readonly selectionSet: SelectionSet;
constructor(schema: Schema, name: string, typeCondition: CompositeType, selectionSet: SelectionSet);
private _selectionSet;
constructor(schema: Schema, name: string, typeCondition: CompositeType, directives?: Directive<NamedFragmentDefinition>[]);
setSelectionSet(selectionSet: SelectionSet): NamedFragmentDefinition;
get selectionSet(): SelectionSet;
withUpdatedSelectionSet(newSelectionSet: SelectionSet): NamedFragmentDefinition;
variables(): Variables;
collectUsedFragmentNames(collector: Map<string, number>): void;

@@ -113,3 +128,2 @@ toFragmentDefinitionNode(): FragmentDefinitionNode;

isEmpty(): boolean;
variables(): Variables;
names(): readonly string[];

@@ -119,19 +133,11 @@ add(fragment: NamedFragmentDefinition): void;

maybeApplyingAtType(type: CompositeType): NamedFragmentDefinition[];
without(names: string[]): NamedFragments;
without(names: string[]): NamedFragments | undefined;
get(name: string): NamedFragmentDefinition | undefined;
has(name: string): boolean;
definitions(): readonly NamedFragmentDefinition[];
validate(): void;
map(mapper: (def: NamedFragmentDefinition) => NamedFragmentDefinition): NamedFragments;
validate(variableDefinitions: VariableDefinitions): void;
toFragmentDefinitionNodes(): FragmentDefinitionNode[];
toString(indent?: string): string;
}
declare abstract class Freezable<T> {
private _isFrozen;
protected abstract us(): T;
freeze(): T;
protected abstract freezeInternals(): void;
isFrozen(): boolean;
cloneIfFrozen(): T;
abstract clone(): T;
}
declare class DeferNormalizer {

@@ -150,34 +156,33 @@ private index;

}
export declare class SelectionSet extends Freezable<SelectionSet> {
export declare class SelectionSet {
readonly parentType: CompositeType;
readonly fragments?: NamedFragments | undefined;
private readonly _keyedSelections;
private readonly _selections;
private _selectionCount;
private _cachedSelections?;
constructor(parentType: CompositeType, fragments?: NamedFragments | undefined);
protected us(): SelectionSet;
selections(reversedOrder?: boolean): readonly Selection[];
constructor(parentType: CompositeType, keyedSelections?: Map<string, Selection>, fragments?: NamedFragments | undefined);
selectionsInReverseOrder(): readonly Selection[];
selections(): readonly Selection[];
hasTopLevelTypenameField(): boolean;
fieldsInSet(): {
path: string[];
field: FieldSelection;
directParent: SelectionSet;
}[];
usedVariables(): Variables;
collectVariables(collector: VariableCollector): void;
collectUsedFragmentNames(collector: Map<string, number>): void;
optimize(fragments?: NamedFragments): SelectionSet;
expandFragments(names?: string[], updateSelectionSetFragments?: boolean): SelectionSet;
lazyMap(mapper: (selection: Selection) => Selection | SelectionSet | undefined): SelectionSet;
expandAllFragments(): SelectionSet;
expandFragments(names: string[], updatedFragments: NamedFragments | undefined): SelectionSet;
trimUnsatisfiableBranches(parentType: CompositeType): SelectionSet;
lazyMap(mapper: (selection: Selection) => Selection | readonly Selection[] | SelectionSet | undefined, options?: {
fragments?: NamedFragments | null;
parentType?: CompositeType;
}): SelectionSet;
private withUpdatedFragments;
withoutDefer(labelsToRemove?: Set<string>): SelectionSet;
withNormalizedDefer(normalizer: DeferNormalizer): SelectionSet;
hasDefer(): boolean;
filter(predicate: (selection: Selection) => boolean): SelectionSet;
withoutEmptyBranches(): SelectionSet | undefined;
protected freezeInternals(): void;
mergeIn(selectionSet: SelectionSet): void;
addAll(selections: readonly Selection[]): SelectionSet;
add(selection: Selection): Selection;
removeTopLevelField(responseName: string): boolean;
addPath(path: OperationPath, onPathEnd?: (finalSelectionSet: SelectionSet | undefined) => void): void;
addSelectionSetNode(node: SelectionSetNode | undefined, variableDefinitions: VariableDefinitions, fieldAccessor?: (type: CompositeType, fieldName: string) => FieldDefinition<any> | undefined): void;
addSelectionNode(node: SelectionNode, variableDefinitions: VariableDefinitions, fieldAccessor?: (type: CompositeType, fieldName: string) => FieldDefinition<any> | undefined): void;
private nodeToSelection;
rebaseOn(parentType: CompositeType): SelectionSet;
equals(that: SelectionSet): boolean;

@@ -187,3 +192,3 @@ contains(that: SelectionSet): boolean;

canRebaseOn(parentTypeToTest: CompositeType): boolean;
validate(): void;
validate(variableDefinitions: VariableDefinitions): void;
isEmpty(): boolean;

@@ -195,65 +200,103 @@ toSelectionSetNode(): SelectionSetNode;

forEachElement(callback: (elt: OperationElement) => void): void;
clone(): SelectionSet;
some(predicate: (elt: OperationElement) => boolean): boolean;
toOperationString(rootKind: SchemaRootKind, variableDefinitions: VariableDefinitions, operationName?: string, expandFragments?: boolean, prettyPrint?: boolean): string;
toString(expandFragments?: boolean, includeExternalBrackets?: boolean, indent?: string): string;
}
export declare class SelectionSetUpdates {
private readonly keyedUpdates;
isEmpty(): boolean;
add(selections: Selection | SelectionSet | readonly Selection[]): SelectionSetUpdates;
addAtPath(path: OperationPath, selections?: Selection | SelectionSet | readonly Selection[]): SelectionSetUpdates;
clone(): SelectionSetUpdates;
clear(): void;
toSelectionSet(parentType: CompositeType, fragments?: NamedFragments): SelectionSet;
}
export declare class MutableSelectionSet<TMemoizedValue extends {
[key: string]: any;
} = {}> {
readonly parentType: CompositeType;
private readonly _updates;
private readonly memoizer;
private computed;
private _memoized;
private constructor();
static empty(parentType: CompositeType): MutableSelectionSet;
static emptyWithMemoized<TMemoizedValue extends {
[key: string]: any;
}>(parentType: CompositeType, memoizer: (s: SelectionSet) => TMemoizedValue): MutableSelectionSet<TMemoizedValue>;
static of(selectionSet: SelectionSet): MutableSelectionSet;
static ofWithMemoized<TMemoizedValue extends {
[key: string]: any;
}>(selectionSet: SelectionSet, memoizer: (s: SelectionSet) => TMemoizedValue): MutableSelectionSet<TMemoizedValue>;
isEmpty(): boolean;
get(): SelectionSet;
updates(): SelectionSetUpdates;
clone(): MutableSelectionSet<TMemoizedValue>;
rebaseOn(parentType: CompositeType): MutableSelectionSet<TMemoizedValue>;
memoized(): TMemoizedValue;
toString(): string;
}
export declare function allFieldDefinitionsInSelectionSet(selection: SelectionSet): FieldDefinition<CompositeType>[];
export declare function selectionSetOfElement(element: OperationElement, subSelection?: SelectionSet): SelectionSet;
export declare function selectionSetOf(parentType: CompositeType, selection: Selection, fragments?: NamedFragments): SelectionSet;
export declare function selectionSetOfElement(element: OperationElement, subSelection?: SelectionSet, fragments?: NamedFragments): SelectionSet;
export declare function selectionOfElement(element: OperationElement, subSelection?: SelectionSet): Selection;
export type Selection = FieldSelection | FragmentSelection;
export declare class FieldSelection extends Freezable<FieldSelection> {
readonly field: Field<any>;
declare abstract class AbstractSelection<TElement extends OperationElement, TIsLeaf extends undefined | never, TOwnType extends AbstractSelection<TElement, TIsLeaf, TOwnType>> {
readonly element: TElement;
constructor(element: TElement);
abstract get selectionSet(): SelectionSet | TIsLeaf;
protected abstract us(): TOwnType;
abstract key(): string;
abstract optimize(fragments: NamedFragments): Selection;
abstract toSelectionNode(): SelectionNode;
abstract validate(variableDefinitions: VariableDefinitions): void;
abstract rebaseOn(parentType: CompositeType): TOwnType;
get parentType(): CompositeType;
collectVariables(collector: VariableCollector): void;
collectUsedFragmentNames(collector: Map<string, number>): void;
namedFragments(): NamedFragments | undefined;
abstract withUpdatedComponents(element: TElement, selectionSet: SelectionSet | TIsLeaf): TOwnType;
withUpdatedSelectionSet(selectionSet: SelectionSet | TIsLeaf): TOwnType;
withUpdatedElement(element: TElement): TOwnType;
mapToSelectionSet(mapper: (s: SelectionSet) => SelectionSet): TOwnType;
abstract withoutDefer(labelsToRemove?: Set<string>): TOwnType | SelectionSet;
abstract withNormalizedDefer(normalizer: DeferNormalizer): TOwnType | SelectionSet;
abstract hasDefer(): boolean;
abstract expandAllFragments(): TOwnType | readonly Selection[];
abstract expandFragments(names: string[], updatedFragments: NamedFragments | undefined): TOwnType | readonly Selection[];
abstract trimUnsatisfiableBranches(parentType: CompositeType): TOwnType | SelectionSet | undefined;
}
export declare class FieldSelection extends AbstractSelection<Field<any>, undefined, FieldSelection> {
private readonly _selectionSet?;
readonly kind: "FieldSelection";
readonly selectionSet?: SelectionSet;
constructor(field: Field<any>, initialSelectionSet?: SelectionSet);
get parentType(): CompositeType;
constructor(field: Field<any>, _selectionSet?: SelectionSet | undefined);
get selectionSet(): SelectionSet | undefined;
protected us(): FieldSelection;
withUpdatedComponents(field: Field<any>, selectionSet: SelectionSet | undefined): FieldSelection;
key(): string;
element(): Field<any>;
usedVariables(): Variables;
collectUsedFragmentNames(collector: Map<string, number>): void;
optimize(fragments: NamedFragments): Selection;
filter(predicate: (selection: Selection) => boolean): FieldSelection | undefined;
protected freezeInternals(): void;
expandFragments(names?: string[], updateSelectionSetFragments?: boolean): FieldSelection;
private fieldArgumentsToAST;
validate(): void;
updateForAddingTo(selectionSet: SelectionSet): FieldSelection;
validate(variableDefinitions: VariableDefinitions): void;
rebaseOn(parentType: CompositeType): FieldSelection;
canAddTo(parentType: CompositeType): boolean;
toSelectionNode(): FieldNode;
withUpdatedSubSelection(newSubSelection: SelectionSet | undefined): FieldSelection;
withUpdatedField(newField: Field<any>): FieldSelection;
withoutDefer(labelsToRemove?: Set<string>): FieldSelection;
withNormalizedDefer(normalizer: DeferNormalizer): FieldSelection;
hasDefer(): boolean;
expandAllFragments(): FieldSelection;
trimUnsatisfiableBranches(_: CompositeType): FieldSelection;
expandFragments(names: string[], updatedFragments: NamedFragments | undefined): FieldSelection;
equals(that: Selection): boolean;
contains(that: Selection): boolean;
namedFragments(): NamedFragments | undefined;
withoutDefer(labelsToRemove?: Set<string>): FieldSelection;
withNormalizedDefer(normalizer: DeferNormalizer): FieldSelection;
clone(): FieldSelection;
toString(expandFragments?: boolean, indent?: string): string;
}
export declare abstract class FragmentSelection extends Freezable<FragmentSelection> {
export declare abstract class FragmentSelection extends AbstractSelection<FragmentElement, never, FragmentSelection> {
readonly kind: "FragmentSelection";
abstract key(): string;
abstract element(): FragmentElement;
abstract get selectionSet(): SelectionSet;
abstract collectUsedFragmentNames(collector: Map<string, number>): void;
abstract namedFragments(): NamedFragments | undefined;
abstract optimize(fragments: NamedFragments): FragmentSelection;
abstract expandFragments(names?: string[]): Selection | readonly Selection[];
abstract toSelectionNode(): SelectionNode;
abstract validate(): void;
abstract withoutDefer(labelsToRemove?: Set<string>): FragmentSelection | SelectionSet;
abstract withNormalizedDefer(normalizer: DeferNormalizer): FragmentSelection | SelectionSet;
abstract updateForAddingTo(selectionSet: SelectionSet): FragmentSelection;
abstract canAddTo(parentType: CompositeType): boolean;
abstract withUpdatedSubSelection(newSubSelection: SelectionSet | undefined): FragmentSelection;
get parentType(): CompositeType;
protected us(): FragmentSelection;
protected validateDeferAndStream(): void;
usedVariables(): Variables;
filter(predicate: (selection: Selection) => boolean): FragmentSelection | undefined;
protected freezeInternals(): void;
hasDefer(): boolean;
equals(that: Selection): boolean;
contains(that: Selection): boolean;
clone(): FragmentSelection;
}

@@ -260,0 +303,0 @@ export declare function operationFromDocument(schema: Schema, document: DocumentNode, options?: {

@@ -32,12 +32,15 @@ "use strict";

for (const provides of field.appliedDirectivesOf(providesDirective)) {
(0, _1.collectTargetFields)({
parentType: (0, _1.baseType)(field.type),
directive: provides,
includeInterfaceFieldsImplementations: true,
validate: false,
}).forEach((f) => {
if (metadata.isFieldExternal(f)) {
shareableFields.add(f.coordinate);
}
});
const parentType = (0, _1.baseType)(field.type);
if ((0, _1.isCompositeType)(parentType)) {
(0, _1.collectTargetFields)({
parentType,
directive: provides,
includeInterfaceFieldsImplementations: true,
validate: false,
}).forEach((f) => {
if (metadata.isFieldExternal(f)) {
shareableFields.add(f.coordinate);
}
});
}
}

@@ -44,0 +47,0 @@ }

@@ -1,2 +0,2 @@

import { ArgumentDefinition, EnumType, InputFieldDefinition, InputType, ScalarType, Schema, VariableDefinitions, Variables } from './definitions';
import { ArgumentDefinition, EnumType, InputFieldDefinition, InputType, ScalarType, Schema, VariableCollector, VariableDefinitions } from './definitions';
import { ArgumentNode, ValueNode, ConstValueNode } from 'graphql';

@@ -21,4 +21,4 @@ export declare function valueToString(v: any, expectedType?: InputType): string;

[key: string]: any;
};
export declare function variablesInValue(value: any): Variables;
} | undefined;
export declare function collectVariablesInValue(value: any, collector: VariableCollector): void;
//# sourceMappingURL=values.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.variablesInValue = exports.argumentsFromAST = exports.isValidLeafValue = exports.valueFromASTUntyped = exports.valueFromAST = exports.isValidValue = exports.valueToAST = exports.valueNodeToConstValueNode = exports.withDefaultValues = exports.argumentsEquals = exports.valueEquals = exports.valueToString = void 0;
exports.collectVariablesInValue = exports.argumentsFromAST = exports.isValidLeafValue = exports.valueFromASTUntyped = exports.valueFromAST = exports.isValidValue = exports.valueToAST = exports.valueNodeToConstValueNode = exports.withDefaultValues = exports.argumentsEquals = exports.valueEquals = exports.valueToString = void 0;
const definitions_1 = require("./definitions");

@@ -541,19 +541,20 @@ const graphql_1 = require("graphql");

var _a;
if (!args || args.length === 0) {
return undefined;
}
const values = Object.create(null);
if (args) {
for (const argNode of args) {
const name = argNode.name.value;
const expectedType = (_a = argsDefiner.argument(name)) === null || _a === void 0 ? void 0 : _a.type;
if (!expectedType) {
throw error_1.ERRORS.INVALID_GRAPHQL.err(`Unknown argument "${name}" found in value: "${context}" has no argument named "${name}"`);
for (const argNode of args) {
const name = argNode.name.value;
const expectedType = (_a = argsDefiner.argument(name)) === null || _a === void 0 ? void 0 : _a.type;
if (!expectedType) {
throw error_1.ERRORS.INVALID_GRAPHQL.err(`Unknown argument "${name}" found in value: "${context}" has no argument named "${name}"`);
}
try {
values[name] = valueFromAST(argNode.value, expectedType);
}
catch (e) {
if (e instanceof graphql_1.GraphQLError) {
throw error_1.ERRORS.INVALID_GRAPHQL.err(`Invalid value for argument "${name}": ${e.message}`);
}
try {
values[name] = valueFromAST(argNode.value, expectedType);
}
catch (e) {
if (e instanceof graphql_1.GraphQLError) {
throw error_1.ERRORS.INVALID_GRAPHQL.err(`Invalid value for argument "${name}": ${e.message}`);
}
throw e;
}
throw e;
}

@@ -564,13 +565,5 @@ }

exports.argumentsFromAST = argumentsFromAST;
function variablesInValue(value) {
const variables = [];
collectVariables(value, variables);
return variables;
}
exports.variablesInValue = variablesInValue;
function collectVariables(value, variables) {
function collectVariablesInValue(value, collector) {
if ((0, definitions_1.isVariable)(value)) {
if (!variables.some(v => v.name === value.name)) {
variables.push(value);
}
collector.add(value);
return;

@@ -582,8 +575,9 @@ }

if (Array.isArray(value)) {
value.forEach(v => collectVariables(v, variables));
value.forEach(v => collectVariablesInValue(v, collector));
}
if (typeof value === 'object') {
Object.keys(value).forEach(k => collectVariables(value[k], variables));
Object.keys(value).forEach(k => collectVariablesInValue(value[k], collector));
}
}
exports.collectVariablesInValue = collectVariablesInValue;
//# sourceMappingURL=values.js.map
{
"name": "@apollo/federation-internals",
"version": "2.4.0-alpha.1",
"version": "2.4.0",
"description": "Apollo Federation internal utilities",

@@ -27,3 +27,5 @@ "main": "dist/index.js",

"chalk": "^4.1.0",
"js-levenshtein": "^1.1.6"
"js-levenshtein": "^1.1.6",
"@types/uuid": "^9.0.0",
"uuid": "^9.0.0"
},

@@ -30,0 +32,0 @@ "publishConfig": {

@@ -7,3 +7,3 @@ import {

import { buildSchema } from '../../dist/buildSchema';
import { Field, FieldSelection, Operation, operationFromDocument, parseOperation, SelectionSet } from '../../dist/operations';
import { MutableSelectionSet, Operation, operationFromDocument, parseOperation } from '../../dist/operations';
import './matchers';

@@ -246,120 +246,2 @@ import { DocumentNode, FieldNode, GraphQLError, Kind, OperationDefinitionNode, OperationTypeNode, SelectionNode, SelectionSetNode } from 'graphql';

describe('selection set freezing', () => {
const schema = parseSchema(`
type Query {
t: T
}
type T {
a: Int
b: Int
}
`);
const tField = schema.schemaDefinition.rootType('query')!.field('t')!;
it('throws if one tries to modify a frozen selection set', () => {
// Note that we use parseOperation to help us build selection/selection sets because it's more readable/convenient
// thant to build the object "programmatically".
const s1 = parseOperation(schema, `{ t { a } }`).selectionSet;
const s2 = parseOperation(schema, `{ t { b } }`).selectionSet;
const s = new SelectionSet(schema.schemaDefinition.rootType('query')!);
// Control: check we can add to the selection set while not yet frozen
expect(s.isFrozen()).toBeFalsy();
expect(() => s.mergeIn(s1)).not.toThrow();
s.freeze();
expect(s.isFrozen()).toBeTruthy();
expect(() => s.mergeIn(s2)).toThrowError('Cannot add to frozen selection: { t { a } }');
});
it('it does not clone non-frozen selections when adding to another one', () => {
// This test is a bit debatable because what it tests is not so much a behaviour
// we *need* absolutely to preserve, but rather test how things happens to
// behave currently and illustrate the current contrast between frozen and
// non-frozen selection set.
// That is, this test show what happens if the test
// "it automaticaly clones frozen selections when adding to another one"
// is done without freezing.
const s1 = parseOperation(schema, `{ t { a } }`).selectionSet;
const s2 = parseOperation(schema, `{ t { b } }`).selectionSet;
const s = new SelectionSet(schema.schemaDefinition.rootType('query')!);
s.mergeIn(s1);
s.mergeIn(s2);
expect(s.toString()).toBe('{ t { a b } }');
// This next assertion is where differs from the case where `s1` is frozen. Namely,
// when we do `s.mergeIn(s1)`, then `s` directly references `s1` without cloning
// and thus the next modification (`s.mergeIn(s2)`) ends up modifying both `s` and `s1`.
// Note that we don't mean by this test that the fact that `s.mergeIn(s1)` does
// not clone `s1` is a behaviour one should *rely* on, but it currently done for
// efficiencies sake: query planning does a lot of selection set building through
// `SelectionSet::mergeIn` and `SelectionSet::add` and we often pass to those method
// newly constructed selections as input, so cloning them would wast CPU and early
// query planning benchmarking showed that this could add up on the more expansive
// plan computations. This is why freezing exists: it allows us to save cloning
// in general, but to protect those selection set we know should be immutable
// so they do get cloned in such situation.
expect(s1.toString()).toBe('{ t { a b } }');
expect(s2.toString()).toBe('{ t { b } }');
});
it('it automaticaly clones frozen field selections when merging to another one', () => {
const s1 = parseOperation(schema, `{ t { a } }`).selectionSet.freeze();
const s2 = parseOperation(schema, `{ t { b } }`).selectionSet.freeze();
const s = new SelectionSet(schema.schemaDefinition.rootType('query')!);
s.mergeIn(s1);
s.mergeIn(s2);
// We check S is what we expect...
expect(s.toString()).toBe('{ t { a b } }');
// ... but more importantly for this test, that s1/s2 were not modified.
expect(s1.toString()).toBe('{ t { a } }');
expect(s2.toString()).toBe('{ t { b } }');
});
it('it automaticaly clones frozen fragment selections when merging to another one', () => {
// Note: needlessly complex queries, but we're just ensuring the cloning story works when fragments are involved
const s1 = parseOperation(schema, `{ ... on Query { t { ... on T { a } } } }`).selectionSet.freeze();
const s2 = parseOperation(schema, `{ ... on Query { t { ... on T { b } } } }`).selectionSet.freeze();
const s = new SelectionSet(schema.schemaDefinition.rootType('query')!);
s.mergeIn(s1);
s.mergeIn(s2);
expect(s.toString()).toBe('{ ... on Query { t { ... on T { a b } } } }');
expect(s1.toString()).toBe('{ ... on Query { t { ... on T { a } } } }');
expect(s2.toString()).toBe('{ ... on Query { t { ... on T { b } } } }');
});
it('it automaticaly clones frozen field selections when adding to another one', () => {
const s1 = parseOperation(schema, `{ t { a } }`).selectionSet.freeze();
const s2 = parseOperation(schema, `{ t { b } }`).selectionSet.freeze();
const s = new SelectionSet(schema.schemaDefinition.rootType('query')!);
const tSelection = new FieldSelection(new Field(tField));
s.add(tSelection);
// Note that this test both checks the auto-cloning for the `add` method, but
// also shows that freezing dose apply deeply (since we freeze the whole `s1`/`s2`
// but only add some sub-selection of it).
tSelection.selectionSet!.add(s1.selections()[0].selectionSet!.selections()[0]);
tSelection.selectionSet!.add(s2.selections()[0].selectionSet!.selections()[0]);
// We check S is what we expect...
expect(s.toString()).toBe('{ t { a b } }');
// ... but more importantly for this test, that s1/s2 were not modified.
expect(s1.toString()).toBe('{ t { a } }');
expect(s2.toString()).toBe('{ t { b } }');
});
});
describe('validations', () => {

@@ -522,1 +404,148 @@ test.each([

});
describe('basic operations', () => {
const schema = parseSchema(`
type Query {
t: T
i: I
}
type T {
v1: Int
v2: String
v3: I
}
interface I {
x: Int
y: Int
}
type A implements I {
x: Int
y: Int
a1: String
a2: String
}
type B implements I {
x: Int
y: Int
b1: Int
b2: T
}
`);
const operation = parseOperation(schema, `
{
t {
v1
v3 {
x
}
}
i {
... on A {
a1
a2
}
... on B {
y
b2 {
v2
}
}
}
}
`);
test('forEachElement', () => {
// We collect a pair of (parent type, field-or-fragment).
const actual: [string, string][] = [];
operation.selectionSet.forEachElement((elt) => actual.push([elt.parentType.name, elt.toString()]));
expect(actual).toStrictEqual([
['Query', 't'],
['T', 'v1'],
['T', 'v3'],
['I', 'x'],
['Query', 'i'],
['I', '... on A'],
['A', 'a1'],
['A', 'a2'],
['I', '... on B'],
['B', 'y'],
['B', 'b2'],
['T', 'v2'],
]);
})
});
describe('MutableSelectionSet', () => {
test('memoizer', () => {
const schema = parseSchema(`
type Query {
t: T
}
type T {
v1: Int
v2: String
v3: Int
v4: Int
}
`);
type Value = {
count: number
};
let calls = 0;
const sets: string[] = [];
const queryType = schema.schemaDefinition.rootType('query')!;
const ss = MutableSelectionSet.emptyWithMemoized<Value>(
queryType,
(s) => {
sets.push(s.toString());
return { count: ++calls };
}
);
expect(ss.memoized().count).toBe(1);
// Calling a 2nd time with no change to make sure we're not re-generating the value.
expect(ss.memoized().count).toBe(1);
ss.updates().add(parseOperation(schema, `{ t { v1 } }`).selectionSet);
expect(ss.memoized().count).toBe(2);
expect(sets).toStrictEqual(['{}', '{ t { v1 } }']);
ss.updates().add(parseOperation(schema, `{ t { v3 } }`).selectionSet);
expect(ss.memoized().count).toBe(3);
expect(sets).toStrictEqual(['{}', '{ t { v1 } }', '{ t { v1 v3 } }']);
// Still making sure we don't re-compute without updates.
expect(ss.memoized().count).toBe(3);
const cloned = ss.clone();
expect(cloned.memoized().count).toBe(3);
cloned.updates().add(parseOperation(schema, `{ t { v2 } }`).selectionSet);
// The value of `ss` should not have be recomputed, so it should still be 3.
expect(ss.memoized().count).toBe(3);
// But that of the clone should have changed.
expect(cloned.memoized().count).toBe(4);
expect(sets).toStrictEqual(['{}', '{ t { v1 } }', '{ t { v1 v3 } }', '{ t { v1 v3 v2 } }']);
// And here we make sure that if we update the fist selection, we don't have v3 in the set received
ss.updates().add(parseOperation(schema, `{ t { v4 } }`).selectionSet);
// Here, only `ss` memoized value has been recomputed. But since both increment the same `calls` variable,
// the total count should be 5 (even if the previous count for `ss` was only 3).
expect(ss.memoized().count).toBe(5);
expect(cloned.memoized().count).toBe(4);
expect(sets).toStrictEqual(['{}', '{ t { v1 } }', '{ t { v1 v3 } }', '{ t { v1 v3 v2 } }', '{ t { v1 v3 v4 } }']);
});
});

@@ -9,2 +9,3 @@ import {

Schema,
isCompositeType,
} from ".";

@@ -45,14 +46,19 @@

for (const provides of field.appliedDirectivesOf(providesDirective)) {
collectTargetFields({
parentType: baseType(field.type!) as CompositeType,
directive: provides,
includeInterfaceFieldsImplementations: true,
validate: false,
}).forEach((f) => {
// Fed2 schema reject provides on non-external field, but fed1 doesn't (at least not always), and we actually
// call this on fed1 schema upgrader. So let's make sure we do ignore non-external fields.
if (metadata.isFieldExternal(f)) {
shareableFields.add(f.coordinate);
}
});
const parentType = baseType(field.type!);
// It's never valid to put a @provides on a non-composite type, but things haven't been fully validated when this
// code run and we just want to ignore non-sensical cases (this is also why we pass `validate: false` below).
if (isCompositeType(parentType)) {
collectTargetFields({
parentType,
directive: provides,
includeInterfaceFieldsImplementations: true,
validate: false,
}).forEach((f) => {
// Fed2 schema reject provides on non-external field, but fed1 doesn't (at least not always), and we actually
// call this on fed1 schema upgrader. So let's make sure we do ignore non-external fields.
if (metadata.isFieldExternal(f)) {
shareableFields.add(f.coordinate);
}
});
}
}

@@ -59,0 +65,0 @@ }

@@ -22,5 +22,5 @@ import {

Variable,
VariableCollector,
VariableDefinition,
VariableDefinitions,
Variables,
} from './definitions';

@@ -701,21 +701,23 @@ import {

argsDefiner: { argument(name: string): ArgumentDefinition<any> | undefined }
): {[key: string]: any} {
): {[key: string]: any} | undefined {
if (!args || args.length === 0) {
return undefined;
}
const values = Object.create(null);
if (args) {
for (const argNode of args) {
const name = argNode.name.value;
const expectedType = argsDefiner.argument(name)?.type;
if (!expectedType) {
throw ERRORS.INVALID_GRAPHQL.err(
`Unknown argument "${name}" found in value: "${context}" has no argument named "${name}"`
);
for (const argNode of args) {
const name = argNode.name.value;
const expectedType = argsDefiner.argument(name)?.type;
if (!expectedType) {
throw ERRORS.INVALID_GRAPHQL.err(
`Unknown argument "${name}" found in value: "${context}" has no argument named "${name}"`
);
}
try {
values[name] = valueFromAST(argNode.value, expectedType);
} catch (e) {
if (e instanceof GraphQLError) {
throw ERRORS.INVALID_GRAPHQL.err(`Invalid value for argument "${name}": ${e.message}`);
}
try {
values[name] = valueFromAST(argNode.value, expectedType);
} catch (e) {
if (e instanceof GraphQLError) {
throw ERRORS.INVALID_GRAPHQL.err(`Invalid value for argument "${name}": ${e.message}`);
}
throw e;
}
throw e;
}

@@ -726,13 +728,5 @@ }

export function variablesInValue(value: any): Variables {
const variables: Variable[] = [];
collectVariables(value, variables);
return variables;
}
function collectVariables(value: any, variables: Variable[]) {
export function collectVariablesInValue(value: any, collector: VariableCollector) {
if (isVariable(value)) {
if (!variables.some(v => v.name === value.name)) {
variables.push(value);
}
collector.add(value);
return;

@@ -746,8 +740,8 @@ }

if (Array.isArray(value)) {
value.forEach(v => collectVariables(v, variables));
value.forEach(v => collectVariablesInValue(v, collector));
}
if (typeof value === 'object') {
Object.keys(value).forEach(k => collectVariables(value[k], variables));
Object.keys(value).forEach(k => collectVariablesInValue(value[k], collector));
}
}

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 too big to display

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc