@ardatan/relay-compiler
Version:
Fork of `relay-compiler`
553 lines (484 loc) • 17 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 invariant = require('invariant');
var _require = require('../util/DefaultHandleKey'),
DEFAULT_HANDLE_KEY = _require.DEFAULT_HANDLE_KEY;
var INDENT = ' ';
/**
* Converts an IR node into a GraphQL string. Custom Relay
* extensions (directives) are not supported; to print fragments with
* variables or fragment spreads with arguments, transform the node
* prior to printing.
*/
function print(schema, node) {
switch (node.kind) {
case 'Fragment':
return (
'fragment '.concat(node.name, ' on ').concat(schema.getTypeString(node.type)) +
printFragmentArgumentDefinitions(schema, node.argumentDefinitions) +
printDirectives(schema, node.directives) +
printSelections(schema, node, '', {}) +
'\n'
);
case 'Root':
return (
''.concat(node.operation, ' ').concat(node.name) +
printArgumentDefinitions(schema, node.argumentDefinitions) +
printDirectives(schema, node.directives) +
printSelections(schema, node, '', {}) +
'\n'
);
case 'SplitOperation':
return (
'SplitOperation '.concat(node.name, ' on ').concat(schema.getTypeString(node.type)) +
printSelections(schema, node, '', {}) +
'\n'
);
default:
node;
!false
? process.env.NODE_ENV !== 'production'
? invariant(false, 'IRPrinter: Unsupported IR node `%s`.', node.kind)
: invariant(false)
: void 0;
}
}
function printSelections(schema, node, indent, options) {
var selections = node.selections;
if (selections == null) {
return '';
}
var printed = selections.map(function (selection) {
return printSelection(schema, selection, indent, options);
});
return printed.length
? ' {\n'
.concat(indent + INDENT)
.concat(printed.join('\n' + indent + INDENT), '\n')
.concat(indent)
.concat(
(options === null || options === void 0 ? void 0 : options.isClientExtension) === true
? '# '
: '',
'}',
)
: '';
}
/**
* Prints a field without subselections.
*/
function printField(schema, field, options) {
var _options$parentDirect;
var parentDirectives =
(_options$parentDirect =
options === null || options === void 0 ? void 0 : options.parentDirectives) !== null &&
_options$parentDirect !== void 0
? _options$parentDirect
: '';
var isClientExtension =
(options === null || options === void 0 ? void 0 : options.isClientExtension) === true;
return (
(isClientExtension ? '# ' : '') +
(field.alias === field.name ? field.name : field.alias + ': ' + field.name) +
printArguments(schema, field.args) +
parentDirectives +
printDirectives(schema, field.directives) +
printHandles(schema, field)
);
}
function printSelection(schema, selection, indent, options) {
var _options$parentDirect2;
var str;
var parentDirectives =
(_options$parentDirect2 =
options === null || options === void 0 ? void 0 : options.parentDirectives) !== null &&
_options$parentDirect2 !== void 0
? _options$parentDirect2
: '';
var isClientExtension =
(options === null || options === void 0 ? void 0 : options.isClientExtension) === true;
if (selection.kind === 'LinkedField') {
str = printField(schema, selection, {
parentDirectives: parentDirectives,
isClientExtension: isClientExtension,
});
str += printSelections(schema, selection, indent + INDENT, {
isClientExtension: isClientExtension,
});
} else if (selection.kind === 'ModuleImport') {
str = selection.selections
.map(function (matchSelection) {
return printSelection(schema, matchSelection, indent, {
parentDirectives: parentDirectives,
isClientExtension: isClientExtension,
});
})
.join('\n' + indent + INDENT);
} else if (selection.kind === 'ScalarField') {
str = printField(schema, selection, {
parentDirectives: parentDirectives,
isClientExtension: isClientExtension,
});
} else if (selection.kind === 'InlineFragment') {
str = '';
if (isClientExtension) {
str += '# ';
}
str += '... on ' + schema.getTypeString(selection.typeCondition);
str += parentDirectives;
str += printDirectives(schema, selection.directives);
str += printSelections(schema, selection, indent + INDENT, {
isClientExtension: isClientExtension,
});
} else if (selection.kind === 'FragmentSpread') {
str = '';
if (isClientExtension) {
str += '# ';
}
str += '...' + selection.name;
str += parentDirectives;
str += printFragmentArguments(schema, selection.args);
str += printDirectives(schema, selection.directives);
} else if (selection.kind === 'InlineDataFragmentSpread') {
str =
'# '.concat(selection.name, ' @inline') +
'\n'.concat(indent).concat(INDENT, '...') +
parentDirectives +
printSelections(schema, selection, indent + INDENT, {});
} else if (selection.kind === 'Condition') {
var value = printValue(schema, selection.condition, null); // For Flow
!(value != null)
? process.env.NODE_ENV !== 'production'
? invariant(false, 'IRPrinter: Expected a variable for condition, got a literal `null`.')
: invariant(false)
: void 0;
var condStr = selection.passingValue ? ' @include' : ' @skip';
condStr += '(if: ' + value + ')';
condStr += parentDirectives; // For multi-selection conditions, pushes the condition down to each
var subSelections = selection.selections.map(function (sel) {
return printSelection(schema, sel, indent, {
parentDirectives: condStr,
isClientExtension: isClientExtension,
});
});
str = subSelections.join('\n' + indent + INDENT);
} else if (selection.kind === 'Stream') {
var streamStr = parentDirectives;
streamStr += ' @stream(label: "'.concat(selection.label, '"');
if (selection['if'] !== null) {
var _printValue;
streamStr += ', if: '.concat(
(_printValue = printValue(schema, selection['if'], null)) !== null && _printValue !== void 0
? _printValue
: '',
);
}
if (selection.initialCount !== null) {
var _printValue2;
streamStr += ', initial_count: '.concat(
(_printValue2 = printValue(schema, selection.initialCount, null)) !== null &&
_printValue2 !== void 0
? _printValue2
: '',
);
}
if (selection.useCustomizedBatch !== null) {
var _printValue3;
streamStr += ', use_customized_batch: '.concat(
(_printValue3 = printValue(schema, selection.useCustomizedBatch, null)) !== null &&
_printValue3 !== void 0
? _printValue3
: 'false',
);
}
streamStr += ')';
var _subSelections = selection.selections.map(function (sel) {
return printSelection(schema, sel, indent, {
parentDirectives: streamStr,
isClientExtension: isClientExtension,
});
});
str = _subSelections.join('\n' + INDENT);
} else if (selection.kind === 'Defer') {
var deferStr = parentDirectives;
deferStr += ' @defer(label: "'.concat(selection.label, '"');
if (selection['if'] !== null) {
var _printValue4;
deferStr += ', if: '.concat(
(_printValue4 = printValue(schema, selection['if'], null)) !== null &&
_printValue4 !== void 0
? _printValue4
: '',
);
}
deferStr += ')';
if (
selection.selections.every(function (subSelection) {
return subSelection.kind === 'InlineFragment' || subSelection.kind === 'FragmentSpread';
})
) {
var _subSelections2 = selection.selections.map(function (sel) {
return printSelection(schema, sel, indent, {
parentDirectives: deferStr,
isClientExtension: isClientExtension,
});
});
str = _subSelections2.join('\n' + INDENT);
} else {
str = '...' + deferStr;
str += printSelections(schema, selection, indent + INDENT, {
isClientExtension: isClientExtension,
});
}
} else if (selection.kind === 'ClientExtension') {
!(isClientExtension === false)
? process.env.NODE_ENV !== 'production'
? invariant(
false,
'IRPrinter: Did not expect to encounter a ClientExtension node ' +
'as a descendant of another ClientExtension node.',
)
: invariant(false)
: void 0;
str =
'# Client-only selections:\n' +
indent +
INDENT +
selection.selections
.map(function (sel) {
return printSelection(schema, sel, indent, {
parentDirectives: parentDirectives,
isClientExtension: true,
});
})
.join('\n' + indent + INDENT);
} else {
selection;
!false
? process.env.NODE_ENV !== 'production'
? invariant(false, 'IRPrinter: Unknown selection kind `%s`.', selection.kind)
: invariant(false)
: void 0;
}
return str;
}
function printArgumentDefinitions(schema, argumentDefinitions) {
var printed = argumentDefinitions.map(function (def) {
var str = '$'.concat(def.name, ': ').concat(schema.getTypeString(def.type));
if (def.defaultValue != null) {
str += ' = ' + printLiteral(schema, def.defaultValue, def.type);
}
return str;
});
return printed.length ? '(\n'.concat(INDENT).concat(printed.join('\n' + INDENT), '\n)') : '';
}
function printFragmentArgumentDefinitions(schema, argumentDefinitions) {
var printed;
argumentDefinitions.forEach(function (def) {
if (def.kind !== 'LocalArgumentDefinition') {
return;
}
printed = printed || [];
var str = ''.concat(def.name, ': {type: "').concat(schema.getTypeString(def.type), '"');
if (def.defaultValue != null) {
str += ', defaultValue: '.concat(printLiteral(schema, def.defaultValue, def.type));
}
str += '}'; // $FlowFixMe[incompatible-use]
printed.push(str);
});
return printed && printed.length
? ' @argumentDefinitions(\n'.concat(INDENT).concat(printed.join('\n' + INDENT), '\n)')
: '';
}
function printHandles(schema, field) {
if (!field.handles) {
return '';
}
var printed = field.handles.map(function (handle) {
// For backward compatibility.
var key = handle.key === DEFAULT_HANDLE_KEY ? '' : ', key: "'.concat(handle.key, '"');
var filters =
handle.filters == null
? ''
: ', filters: '.concat(JSON.stringify(Array.from(handle.filters).sort()));
var handleArgs =
handle.handleArgs == null
? ''
: ', handleArgs: '.concat(printArguments(schema, handle.handleArgs));
return '@__clientField(handle: "'
.concat(handle.name, '"')
.concat(key)
.concat(filters)
.concat(handleArgs, ')');
});
return printed.length ? ' ' + printed.join(' ') : '';
}
function printDirectives(schema, directives) {
var printed = directives.map(function (directive) {
return '@' + directive.name + printArguments(schema, directive.args);
});
return printed.length ? ' ' + printed.join(' ') : '';
}
function printFragmentArguments(schema, args) {
var printedArgs = printArguments(schema, args);
if (!printedArgs.length) {
return '';
}
return ' @arguments'.concat(printedArgs);
}
function printArguments(schema, args) {
var printed = [];
args.forEach(function (arg) {
var printedValue = printValue(schema, arg.value, arg.type);
if (printedValue != null) {
printed.push(arg.name + ': ' + printedValue);
}
});
return printed.length ? '(' + printed.join(', ') + ')' : '';
}
function printValue(schema, value, type) {
if (type != null && schema.isNonNull(type)) {
type = schema.getNullableType(type);
}
if (value.kind === 'Variable') {
return '$' + value.variableName;
} else if (value.kind === 'ObjectValue') {
var inputType = type != null ? schema.asInputObjectType(type) : null;
var pairs = value.fields
.map(function (field) {
var fieldConfig =
inputType != null
? schema.hasField(inputType, field.name)
? schema.getFieldConfig(schema.expectField(inputType, field.name))
: null
: null;
var innerValue = printValue(
schema,
field.value,
fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.type,
);
return innerValue == null ? null : field.name + ': ' + innerValue;
})
.filter(Boolean);
return '{' + pairs.join(', ') + '}';
} else if (value.kind === 'ListValue') {
!(type && schema.isList(type))
? process.env.NODE_ENV !== 'production'
? invariant(false, 'GraphQLIRPrinter: Need a type in order to print arrays.')
: invariant(false)
: void 0;
var innerType = schema.getListItemType(type);
return '['.concat(
value.items
.map(function (i) {
return printValue(schema, i, innerType);
})
.join(', '),
']',
);
} else if (value.value != null) {
return printLiteral(schema, value.value, type);
} else {
return null;
}
}
function printLiteral(schema, value, type) {
if (value == null) {
var _JSON$stringify;
return (_JSON$stringify = JSON.stringify(value)) !== null && _JSON$stringify !== void 0
? _JSON$stringify
: 'null';
}
if (type != null && schema.isNonNull(type)) {
type = schema.getNullableType(type);
}
if (type && schema.isEnum(type)) {
var _JSON$stringify2;
var result = schema.serialize(schema.assertEnumType(type), value);
if (result == null && typeof value === 'string') {
// For backwards compatibility, print invalid input values as-is. This
// can occur with literals defined as an @argumentDefinitions
// defaultValue.
result = value;
}
!(typeof result === 'string')
? process.env.NODE_ENV !== 'production'
? invariant(
false,
'IRPrinter: Expected value of type %s to be a valid enum value, got `%s`.',
schema.getTypeString(type),
(_JSON$stringify2 = JSON.stringify(value)) !== null && _JSON$stringify2 !== void 0
? _JSON$stringify2
: 'null',
)
: invariant(false)
: void 0;
return result;
} else if (type && (schema.isId(type) || schema.isInt(type))) {
var _JSON$stringify3;
return (_JSON$stringify3 = JSON.stringify(value)) !== null && _JSON$stringify3 !== void 0
? _JSON$stringify3
: '';
} else if (type && schema.isScalar(type)) {
var _JSON$stringify4;
var _result = schema.serialize(schema.assertScalarType(type), value);
return (_JSON$stringify4 = JSON.stringify(_result)) !== null && _JSON$stringify4 !== void 0
? _JSON$stringify4
: '';
} else if (Array.isArray(value)) {
!(type && schema.isList(type))
? process.env.NODE_ENV !== 'production'
? invariant(false, 'IRPrinter: Need a type in order to print arrays.')
: invariant(false)
: void 0;
var itemType = schema.getListItemType(type);
return (
'[' +
value
.map(function (item) {
return printLiteral(schema, item, itemType);
})
.join(', ') +
']'
);
} else if (type && schema.isList(type) && value != null) {
// Not an array, but still a list. Treat as list-of-one as per spec 3.1.7:
// http://facebook.github.io/graphql/October2016/#sec-Lists
return printLiteral(schema, value, schema.getListItemType(type));
} else if (typeof value === 'object' && value != null) {
var fields = [];
!(type && schema.isInputObject(type))
? process.env.NODE_ENV !== 'production'
? invariant(false, 'IRPrinter: Need an InputObject type to print objects.')
: invariant(false)
: void 0;
var inputType = schema.assertInputObjectType(type);
for (var key in value) {
if (value.hasOwnProperty(key)) {
var fieldConfig = schema.getFieldConfig(schema.expectField(inputType, key));
fields.push(key + ': ' + printLiteral(schema, value[key], fieldConfig.type));
}
}
return '{' + fields.join(', ') + '}';
} else {
var _JSON$stringify5;
return (_JSON$stringify5 = JSON.stringify(value)) !== null && _JSON$stringify5 !== void 0
? _JSON$stringify5
: 'null';
}
}
module.exports = {
print: print,
printField: printField,
printArguments: printArguments,
printDirectives: printDirectives,
};