@ardatan/relay-compiler
Version:
Fork of `relay-compiler`
137 lines (119 loc) • 3.62 kB
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.
*
*
* @format
*/
// flowlint ambiguous-object-type:error
;
var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault');
var _createForOfIteratorHelper2 = _interopRequireDefault(
require('@babel/runtime/helpers/createForOfIteratorHelper'),
);
var IRValidator = require('../core/IRValidator');
var _require = require('../core/CompilerError'),
createUserError = _require.createUserError;
var NODEKIND_DIRECTIVE_MAP = {
Defer: 'defer',
Stream: 'stream',
};
/*
* Validate that server-only directives are not used inside client fields
*/
function validateServerOnlyDirectives(context) {
IRValidator.validate(
context,
{
ClientExtension: visitClientExtension,
Defer: visitTransformedDirective,
Stream: visitTransformedDirective,
LinkedField: visitLinkedField,
ScalarField: stopVisit,
},
function () {
return {
rootClientSelection: null,
};
},
);
return context;
} // If an empty visitor is defined, we no longer automatically visit child nodes
// such as arguments.
function stopVisit() {} // Only visits selections as an optimization to not look at arguments
function visitLinkedField(node, state) {
var _iterator = (0, _createForOfIteratorHelper2['default'])(node.selections),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done; ) {
var selection = _step.value;
// $FlowFixMe[incompatible-use]
this.visit(selection, state);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
function visitClientExtension(node, state) {
var _iterator2 = (0, _createForOfIteratorHelper2['default'])(node.selections),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) {
var selection = _step2.value;
// $FlowFixMe[incompatible-use]
this.visit(selection, {
rootClientSelection: selection,
});
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
function visitTransformedDirective(node, state) {
if (state.rootClientSelection) {
throwError(
'@'.concat(NODEKIND_DIRECTIVE_MAP[node.kind]),
node.loc,
state.rootClientSelection.loc,
);
} // directive used only on client fields
if (
node.selections.every(function (sel) {
return sel.kind === 'ClientExtension';
})
) {
var _clientExtension$sele;
var clientExtension = node.selections[0];
throwError(
'@'.concat(NODEKIND_DIRECTIVE_MAP[node.kind]),
node.loc,
clientExtension && clientExtension.kind === 'ClientExtension'
? (_clientExtension$sele = clientExtension.selections[0]) === null ||
_clientExtension$sele === void 0
? void 0
: _clientExtension$sele.loc
: null,
);
} // $FlowFixMe[incompatible-use]
this.traverse(node, state);
}
function throwError(directiveName, directiveLoc, clientExtensionLoc) {
throw createUserError(
'Unexpected directive: '.concat(directiveName, '. ') +
'This directive can only be used on fields/fragments that are ' +
'fetched from the server schema, but it is used ' +
'inside a client-only selection.',
clientExtensionLoc == null || directiveLoc === clientExtensionLoc
? [directiveLoc]
: [directiveLoc, clientExtensionLoc],
);
}
module.exports = {
transform: validateServerOnlyDirectives,
};