152 lines
4.2 KiB
JavaScript
152 lines
4.2 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* strict-local
|
|
* @format
|
|
*/
|
|
'use strict';
|
|
|
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
|
|
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread"));
|
|
|
|
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
|
|
var GraphQLCompilerContext = require("./GraphQLCompilerContext");
|
|
|
|
var GraphQLIRTransformer = require("./GraphQLIRTransformer");
|
|
|
|
var invariant = require("fbjs/lib/invariant");
|
|
|
|
var FAIL = 'fail';
|
|
var PASS = 'pass';
|
|
var VARIABLE = 'variable';
|
|
/**
|
|
* A tranform that removes unreachable IR nodes from all documents in a corpus.
|
|
* The following nodes are removed:
|
|
* - Any node with `@include(if: false)`
|
|
* - Any node with `@skip(if: true)`
|
|
* - Any node with empty `selections`
|
|
*/
|
|
|
|
function skipUnreachableNodeTransform(context) {
|
|
var fragments = new Map();
|
|
var nextContext = GraphQLIRTransformer.transform(context, {
|
|
Root: function Root(node) {
|
|
return transformNode(context, fragments, node);
|
|
},
|
|
// Fragments are included below where referenced.
|
|
// Unreferenced fragments are not included.
|
|
Fragment: function Fragment(id) {
|
|
return null;
|
|
}
|
|
});
|
|
return Array.from(fragments.values()).reduce(function (ctx, fragment) {
|
|
return fragment ? ctx.add(fragment) : ctx;
|
|
}, nextContext);
|
|
}
|
|
|
|
function transformNode(context, fragments, node) {
|
|
var queue = (0, _toConsumableArray2["default"])(node.selections);
|
|
var selections;
|
|
|
|
while (queue.length) {
|
|
var selection = queue.shift();
|
|
var nextSelection = void 0;
|
|
|
|
switch (selection.kind) {
|
|
case 'Condition':
|
|
var match = testCondition(selection);
|
|
|
|
if (match === PASS) {
|
|
queue.unshift.apply(queue, (0, _toConsumableArray2["default"])(selection.selections));
|
|
} else if (match === VARIABLE) {
|
|
nextSelection = transformNode(context, fragments, selection);
|
|
}
|
|
|
|
break;
|
|
|
|
case 'FragmentSpread':
|
|
{
|
|
// Skip fragment spreads if the referenced fragment is empty
|
|
if (!fragments.has(selection.name)) {
|
|
var fragment = context.getFragment(selection.name);
|
|
var nextFragment = transformNode(context, fragments, fragment);
|
|
fragments.set(selection.name, nextFragment);
|
|
}
|
|
|
|
if (fragments.get(selection.name)) {
|
|
nextSelection = selection;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 'MatchBranch':
|
|
nextSelection = transformNode(context, fragments, selection);
|
|
break;
|
|
|
|
case 'LinkedField':
|
|
nextSelection = transformNode(context, fragments, selection);
|
|
break;
|
|
|
|
case 'InlineFragment':
|
|
// TODO combine with the LinkedField case when flow supports this
|
|
nextSelection = transformNode(context, fragments, selection);
|
|
break;
|
|
|
|
case 'Defer':
|
|
nextSelection = transformNode(context, fragments, selection);
|
|
break;
|
|
|
|
case 'Stream':
|
|
nextSelection = transformNode(context, fragments, selection);
|
|
break;
|
|
|
|
case 'ScalarField':
|
|
nextSelection = selection;
|
|
break;
|
|
|
|
case 'MatchField':
|
|
nextSelection = transformNode(context, fragments, selection);
|
|
break;
|
|
|
|
default:
|
|
selection.kind;
|
|
!false ? process.env.NODE_ENV !== "production" ? invariant(false, 'SkipUnreachableNodeTransform: Unexpected selection kind `%s`.', selection.kind) : invariant(false) : void 0;
|
|
}
|
|
|
|
if (nextSelection) {
|
|
selections = selections || [];
|
|
selections.push(nextSelection);
|
|
}
|
|
}
|
|
|
|
if (selections) {
|
|
return (0, _objectSpread2["default"])({}, node, {
|
|
selections: selections
|
|
});
|
|
}
|
|
|
|
return null;
|
|
}
|
|
/**
|
|
* Determines whether a condition statically passes/fails or is unknown
|
|
* (variable).
|
|
*/
|
|
|
|
|
|
function testCondition(condition) {
|
|
if (condition.condition.kind === 'Variable') {
|
|
return VARIABLE;
|
|
}
|
|
|
|
return condition.condition.value === condition.passingValue ? PASS : FAIL;
|
|
}
|
|
|
|
module.exports = {
|
|
transform: skipUnreachableNodeTransform
|
|
}; |