@vendure/core
Version:
A modern, headless ecommerce framework
87 lines • 3.37 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.graphqlFields = graphqlFields;
/**
* Walks a `GraphQLResolveInfo` and produces a nested object describing the
* fields the client has selected on this resolver's return type.
*
* Vendored from `graphql-fields@2.0.3`:
* - Source: https://github.com/robrichard/graphql-fields
* - Copyright (c) 2016 Rob Richard
* - Licence: MIT (https://github.com/robrichard/graphql-fields/blob/master/LICENSE)
*
* Trimmed to the subset Vendure actually uses — the `processArguments` and
* `excludedFields` options upstream supports are omitted because the single
* call site (`@Relations()` decorator) never passes them.
*
* Supports:
* - direct field selections
* - inline fragments (`... on Type { ... }`)
* - named fragment spreads (`...FragmentName`)
* - `@skip(if: ...)` and `@include(if: ...)` directives, including those
* reading from `info.variableValues`
* - field merging when the same field appears multiple times across
* fragments (later occurrences extend earlier ones)
*/
function graphqlFields(info) {
return info.fieldNodes.reduce((tree, node) => flattenSelection(node, info, tree), {});
}
function flattenSelection(node, info, tree) {
var _a, _b;
const selections = (_b = (_a = node.selectionSet) === null || _a === void 0 ? void 0 : _a.selections) !== null && _b !== void 0 ? _b : [];
for (const selection of selections) {
if (!shouldInclude(selection, info)) {
continue;
}
if (selection.kind === 'InlineFragment') {
flattenSelection(selection, info, tree);
}
else if (selection.kind === 'FragmentSpread') {
const fragment = info.fragments[selection.name.value];
if (fragment) {
flattenSelection(fragment, info, tree);
}
}
else {
const name = selection.name.value;
const existing = tree[name];
tree[name] = flattenSelection(selection, info, existing !== null && existing !== void 0 ? existing : {});
}
}
return tree;
}
function shouldInclude(selection, info) {
var _a;
const directives = selection.directives;
if (!directives || directives.length === 0) {
return true;
}
for (const directive of directives) {
const name = directive.name.value;
if (name !== 'skip' && name !== 'include') {
continue;
}
const arg = (_a = directive.arguments) === null || _a === void 0 ? void 0 : _a[0];
if (!arg) {
continue;
}
const condition = resolveBooleanArgument(arg, info);
if (name === 'skip' && condition === true)
return false;
if (name === 'include' && condition === false)
return false;
}
return true;
}
function resolveBooleanArgument(arg, info) {
if (arg.value.kind === 'BooleanValue') {
return arg.value.value;
}
if (arg.value.kind === 'Variable') {
return Boolean(info.variableValues[arg.value.name.value]);
}
// `@skip`/`@include` are spec-typed as `Boolean!`, so unreachable in any valid
// query — but stay conservative: treat as false to leave fields visible by default.
return false;
}
//# sourceMappingURL=graphql-fields.js.map