transform.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var tslib_1 = require("tslib");
  4. var visitor_1 = require("graphql/language/visitor");
  5. var getFromAST_1 = require("./getFromAST");
  6. var filterInPlace_1 = require("./util/filterInPlace");
  7. var ts_invariant_1 = require("ts-invariant");
  8. var storeUtils_1 = require("./storeUtils");
  9. var TYPENAME_FIELD = {
  10. kind: 'Field',
  11. name: {
  12. kind: 'Name',
  13. value: '__typename',
  14. },
  15. };
  16. function isEmpty(op, fragments) {
  17. return op.selectionSet.selections.every(function (selection) {
  18. return selection.kind === 'FragmentSpread' &&
  19. isEmpty(fragments[selection.name.value], fragments);
  20. });
  21. }
  22. function nullIfDocIsEmpty(doc) {
  23. return isEmpty(getFromAST_1.getOperationDefinition(doc) || getFromAST_1.getFragmentDefinition(doc), getFromAST_1.createFragmentMap(getFromAST_1.getFragmentDefinitions(doc)))
  24. ? null
  25. : doc;
  26. }
  27. function getDirectiveMatcher(directives) {
  28. return function directiveMatcher(directive) {
  29. return directives.some(function (dir) {
  30. return (dir.name && dir.name === directive.name.value) ||
  31. (dir.test && dir.test(directive));
  32. });
  33. };
  34. }
  35. function removeDirectivesFromDocument(directives, doc) {
  36. var variablesInUse = Object.create(null);
  37. var variablesToRemove = [];
  38. var fragmentSpreadsInUse = Object.create(null);
  39. var fragmentSpreadsToRemove = [];
  40. var modifiedDoc = nullIfDocIsEmpty(visitor_1.visit(doc, {
  41. Variable: {
  42. enter: function (node, _key, parent) {
  43. if (parent.kind !== 'VariableDefinition') {
  44. variablesInUse[node.name.value] = true;
  45. }
  46. },
  47. },
  48. Field: {
  49. enter: function (node) {
  50. if (directives && node.directives) {
  51. var shouldRemoveField = directives.some(function (directive) { return directive.remove; });
  52. if (shouldRemoveField &&
  53. node.directives &&
  54. node.directives.some(getDirectiveMatcher(directives))) {
  55. if (node.arguments) {
  56. node.arguments.forEach(function (arg) {
  57. if (arg.value.kind === 'Variable') {
  58. variablesToRemove.push({
  59. name: arg.value.name.value,
  60. });
  61. }
  62. });
  63. }
  64. if (node.selectionSet) {
  65. getAllFragmentSpreadsFromSelectionSet(node.selectionSet).forEach(function (frag) {
  66. fragmentSpreadsToRemove.push({
  67. name: frag.name.value,
  68. });
  69. });
  70. }
  71. return null;
  72. }
  73. }
  74. },
  75. },
  76. FragmentSpread: {
  77. enter: function (node) {
  78. fragmentSpreadsInUse[node.name.value] = true;
  79. },
  80. },
  81. Directive: {
  82. enter: function (node) {
  83. if (getDirectiveMatcher(directives)(node)) {
  84. return null;
  85. }
  86. },
  87. },
  88. }));
  89. if (modifiedDoc &&
  90. filterInPlace_1.filterInPlace(variablesToRemove, function (v) { return !variablesInUse[v.name]; }).length) {
  91. modifiedDoc = removeArgumentsFromDocument(variablesToRemove, modifiedDoc);
  92. }
  93. if (modifiedDoc &&
  94. filterInPlace_1.filterInPlace(fragmentSpreadsToRemove, function (fs) { return !fragmentSpreadsInUse[fs.name]; })
  95. .length) {
  96. modifiedDoc = removeFragmentSpreadFromDocument(fragmentSpreadsToRemove, modifiedDoc);
  97. }
  98. return modifiedDoc;
  99. }
  100. exports.removeDirectivesFromDocument = removeDirectivesFromDocument;
  101. function addTypenameToDocument(doc) {
  102. return visitor_1.visit(getFromAST_1.checkDocument(doc), {
  103. SelectionSet: {
  104. enter: function (node, _key, parent) {
  105. if (parent &&
  106. parent.kind === 'OperationDefinition') {
  107. return;
  108. }
  109. var selections = node.selections;
  110. if (!selections) {
  111. return;
  112. }
  113. var skip = selections.some(function (selection) {
  114. return (storeUtils_1.isField(selection) &&
  115. (selection.name.value === '__typename' ||
  116. selection.name.value.lastIndexOf('__', 0) === 0));
  117. });
  118. if (skip) {
  119. return;
  120. }
  121. var field = parent;
  122. if (storeUtils_1.isField(field) &&
  123. field.directives &&
  124. field.directives.some(function (d) { return d.name.value === 'export'; })) {
  125. return;
  126. }
  127. return tslib_1.__assign(tslib_1.__assign({}, node), { selections: tslib_1.__spreadArrays(selections, [TYPENAME_FIELD]) });
  128. },
  129. },
  130. });
  131. }
  132. exports.addTypenameToDocument = addTypenameToDocument;
  133. var connectionRemoveConfig = {
  134. test: function (directive) {
  135. var willRemove = directive.name.value === 'connection';
  136. if (willRemove) {
  137. if (!directive.arguments ||
  138. !directive.arguments.some(function (arg) { return arg.name.value === 'key'; })) {
  139. ts_invariant_1.invariant.warn('Removing an @connection directive even though it does not have a key. ' +
  140. 'You may want to use the key parameter to specify a store key.');
  141. }
  142. }
  143. return willRemove;
  144. },
  145. };
  146. function removeConnectionDirectiveFromDocument(doc) {
  147. return removeDirectivesFromDocument([connectionRemoveConfig], getFromAST_1.checkDocument(doc));
  148. }
  149. exports.removeConnectionDirectiveFromDocument = removeConnectionDirectiveFromDocument;
  150. function hasDirectivesInSelectionSet(directives, selectionSet, nestedCheck) {
  151. if (nestedCheck === void 0) { nestedCheck = true; }
  152. return (selectionSet &&
  153. selectionSet.selections &&
  154. selectionSet.selections.some(function (selection) {
  155. return hasDirectivesInSelection(directives, selection, nestedCheck);
  156. }));
  157. }
  158. function hasDirectivesInSelection(directives, selection, nestedCheck) {
  159. if (nestedCheck === void 0) { nestedCheck = true; }
  160. if (!storeUtils_1.isField(selection)) {
  161. return true;
  162. }
  163. if (!selection.directives) {
  164. return false;
  165. }
  166. return (selection.directives.some(getDirectiveMatcher(directives)) ||
  167. (nestedCheck &&
  168. hasDirectivesInSelectionSet(directives, selection.selectionSet, nestedCheck)));
  169. }
  170. function getDirectivesFromDocument(directives, doc) {
  171. getFromAST_1.checkDocument(doc);
  172. var parentPath;
  173. return nullIfDocIsEmpty(visitor_1.visit(doc, {
  174. SelectionSet: {
  175. enter: function (node, _key, _parent, path) {
  176. var currentPath = path.join('-');
  177. if (!parentPath ||
  178. currentPath === parentPath ||
  179. !currentPath.startsWith(parentPath)) {
  180. if (node.selections) {
  181. var selectionsWithDirectives = node.selections.filter(function (selection) { return hasDirectivesInSelection(directives, selection); });
  182. if (hasDirectivesInSelectionSet(directives, node, false)) {
  183. parentPath = currentPath;
  184. }
  185. return tslib_1.__assign(tslib_1.__assign({}, node), { selections: selectionsWithDirectives });
  186. }
  187. else {
  188. return null;
  189. }
  190. }
  191. },
  192. },
  193. }));
  194. }
  195. exports.getDirectivesFromDocument = getDirectivesFromDocument;
  196. function getArgumentMatcher(config) {
  197. return function argumentMatcher(argument) {
  198. return config.some(function (aConfig) {
  199. return argument.value &&
  200. argument.value.kind === 'Variable' &&
  201. argument.value.name &&
  202. (aConfig.name === argument.value.name.value ||
  203. (aConfig.test && aConfig.test(argument)));
  204. });
  205. };
  206. }
  207. function removeArgumentsFromDocument(config, doc) {
  208. var argMatcher = getArgumentMatcher(config);
  209. return nullIfDocIsEmpty(visitor_1.visit(doc, {
  210. OperationDefinition: {
  211. enter: function (node) {
  212. return tslib_1.__assign(tslib_1.__assign({}, node), { variableDefinitions: node.variableDefinitions.filter(function (varDef) {
  213. return !config.some(function (arg) { return arg.name === varDef.variable.name.value; });
  214. }) });
  215. },
  216. },
  217. Field: {
  218. enter: function (node) {
  219. var shouldRemoveField = config.some(function (argConfig) { return argConfig.remove; });
  220. if (shouldRemoveField) {
  221. var argMatchCount_1 = 0;
  222. node.arguments.forEach(function (arg) {
  223. if (argMatcher(arg)) {
  224. argMatchCount_1 += 1;
  225. }
  226. });
  227. if (argMatchCount_1 === 1) {
  228. return null;
  229. }
  230. }
  231. },
  232. },
  233. Argument: {
  234. enter: function (node) {
  235. if (argMatcher(node)) {
  236. return null;
  237. }
  238. },
  239. },
  240. }));
  241. }
  242. exports.removeArgumentsFromDocument = removeArgumentsFromDocument;
  243. function removeFragmentSpreadFromDocument(config, doc) {
  244. function enter(node) {
  245. if (config.some(function (def) { return def.name === node.name.value; })) {
  246. return null;
  247. }
  248. }
  249. return nullIfDocIsEmpty(visitor_1.visit(doc, {
  250. FragmentSpread: { enter: enter },
  251. FragmentDefinition: { enter: enter },
  252. }));
  253. }
  254. exports.removeFragmentSpreadFromDocument = removeFragmentSpreadFromDocument;
  255. function getAllFragmentSpreadsFromSelectionSet(selectionSet) {
  256. var allFragments = [];
  257. selectionSet.selections.forEach(function (selection) {
  258. if ((storeUtils_1.isField(selection) || storeUtils_1.isInlineFragment(selection)) &&
  259. selection.selectionSet) {
  260. getAllFragmentSpreadsFromSelectionSet(selection.selectionSet).forEach(function (frag) { return allFragments.push(frag); });
  261. }
  262. else if (selection.kind === 'FragmentSpread') {
  263. allFragments.push(selection);
  264. }
  265. });
  266. return allFragments;
  267. }
  268. function buildQueryFromSelectionSet(document) {
  269. var definition = getFromAST_1.getMainDefinition(document);
  270. var definitionOperation = definition.operation;
  271. if (definitionOperation === 'query') {
  272. return document;
  273. }
  274. var modifiedDoc = visitor_1.visit(document, {
  275. OperationDefinition: {
  276. enter: function (node) {
  277. return tslib_1.__assign(tslib_1.__assign({}, node), { operation: 'query' });
  278. },
  279. },
  280. });
  281. return modifiedDoc;
  282. }
  283. exports.buildQueryFromSelectionSet = buildQueryFromSelectionSet;
  284. function removeClientSetsFromDocument(document) {
  285. getFromAST_1.checkDocument(document);
  286. var modifiedDoc = removeDirectivesFromDocument([
  287. {
  288. test: function (directive) { return directive.name.value === 'client'; },
  289. remove: true,
  290. },
  291. ], document);
  292. if (modifiedDoc) {
  293. modifiedDoc = visitor_1.visit(modifiedDoc, {
  294. FragmentDefinition: {
  295. enter: function (node) {
  296. if (node.selectionSet) {
  297. var isTypenameOnly = node.selectionSet.selections.every(function (selection) {
  298. return storeUtils_1.isField(selection) && selection.name.value === '__typename';
  299. });
  300. if (isTypenameOnly) {
  301. return null;
  302. }
  303. }
  304. },
  305. },
  306. });
  307. }
  308. return modifiedDoc;
  309. }
  310. exports.removeClientSetsFromDocument = removeClientSetsFromDocument;
  311. //# sourceMappingURL=transform.js.map