@graphql-tools/merge 8.3.18 → 8.4.0-alpha-20230301043849-3d59d581

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,19 +3,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.mergeArguments = void 0;
4
4
  const utils_1 = require("@graphql-tools/utils");
5
5
  function mergeArguments(args1, args2, config) {
6
- const result = deduplicateArguments([...args2, ...args1].filter(utils_1.isSome));
6
+ const result = deduplicateArguments([...args2, ...args1].filter(utils_1.isSome), config);
7
7
  if (config && config.sort) {
8
8
  result.sort(utils_1.compareNodes);
9
9
  }
10
10
  return result;
11
11
  }
12
12
  exports.mergeArguments = mergeArguments;
13
- function deduplicateArguments(args) {
13
+ function deduplicateArguments(args, config) {
14
14
  return args.reduce((acc, current) => {
15
- const dup = acc.find(arg => arg.name.value === current.name.value);
16
- if (!dup) {
15
+ const dupIndex = acc.findIndex(arg => arg.name.value === current.name.value);
16
+ if (dupIndex === -1) {
17
17
  return acc.concat([current]);
18
18
  }
19
+ else if (!(config === null || config === void 0 ? void 0 : config.reverseArguments)) {
20
+ acc[dupIndex] = current;
21
+ }
19
22
  return acc;
20
23
  }, []);
21
24
  }
@@ -5,16 +5,9 @@ const utils_js_1 = require("./utils.js");
5
5
  const directives_js_1 = require("./directives.js");
6
6
  const utils_1 = require("@graphql-tools/utils");
7
7
  const arguments_js_1 = require("./arguments.js");
8
- function fieldAlreadyExists(fieldsArr, otherField, config) {
9
- const result = fieldsArr.find(field => field.name.value === otherField.name.value);
10
- if (result && !(config === null || config === void 0 ? void 0 : config.ignoreFieldConflicts)) {
11
- const t1 = (0, utils_js_1.extractType)(result.type);
12
- const t2 = (0, utils_js_1.extractType)(otherField.type);
13
- if (t1.name.value !== t2.name.value) {
14
- throw new Error(`Field "${otherField.name.value}" already defined with a different type. Declared as "${t1.name.value}", but you tried to override with "${t2.name.value}"`);
15
- }
16
- }
17
- return !!result;
8
+ function fieldAlreadyExists(fieldsArr, otherField) {
9
+ const resultIndex = fieldsArr.findIndex(field => field.name.value === otherField.name.value);
10
+ return [resultIndex > -1 ? fieldsArr[resultIndex] : null, resultIndex];
18
11
  }
19
12
  function mergeFields(type, f1, f2, config) {
20
13
  const result = [];
@@ -23,22 +16,14 @@ function mergeFields(type, f1, f2, config) {
23
16
  }
24
17
  if (f1 != null) {
25
18
  for (const field of f1) {
26
- if (fieldAlreadyExists(result, field, config)) {
27
- const existing = result.find((f) => f.name.value === field.name.value);
28
- if (!(config === null || config === void 0 ? void 0 : config.ignoreFieldConflicts)) {
29
- if (config === null || config === void 0 ? void 0 : config.throwOnConflict) {
30
- preventConflicts(type, existing, field, false);
31
- }
32
- else {
33
- preventConflicts(type, existing, field, true);
34
- }
35
- if ((0, utils_js_1.isNonNullTypeNode)(field.type) && !(0, utils_js_1.isNonNullTypeNode)(existing.type)) {
36
- existing.type = field.type;
37
- }
38
- }
39
- existing.arguments = (0, arguments_js_1.mergeArguments)(field['arguments'] || [], existing.arguments || [], config);
40
- existing.directives = (0, directives_js_1.mergeDirectives)(field.directives, existing.directives, config);
41
- existing.description = field.description || existing.description;
19
+ const [existing, existingIndex] = fieldAlreadyExists(result, field);
20
+ if (existing && !(config === null || config === void 0 ? void 0 : config.ignoreFieldConflicts)) {
21
+ const newField = ((config === null || config === void 0 ? void 0 : config.onFieldTypeConflict) && config.onFieldTypeConflict(existing, field, type, config === null || config === void 0 ? void 0 : config.throwOnConflict)) ||
22
+ preventConflicts(type, existing, field, config === null || config === void 0 ? void 0 : config.throwOnConflict);
23
+ newField.arguments = (0, arguments_js_1.mergeArguments)(field['arguments'] || [], existing['arguments'] || [], config);
24
+ newField.directives = (0, directives_js_1.mergeDirectives)(field.directives, existing.directives, config);
25
+ newField.description = field.description || existing.description;
26
+ result[existingIndex] = newField;
42
27
  }
43
28
  else {
44
29
  result.push(field);
@@ -58,9 +43,20 @@ exports.mergeFields = mergeFields;
58
43
  function preventConflicts(type, a, b, ignoreNullability = false) {
59
44
  const aType = (0, utils_js_1.printTypeNode)(a.type);
60
45
  const bType = (0, utils_js_1.printTypeNode)(b.type);
61
- if (aType !== bType && !safeChangeForFieldType(a.type, b.type, ignoreNullability)) {
62
- throw new Error(`Field '${type.name.value}.${a.name.value}' changed type from '${aType}' to '${bType}'`);
46
+ if (aType !== bType) {
47
+ const t1 = (0, utils_js_1.extractType)(a.type);
48
+ const t2 = (0, utils_js_1.extractType)(b.type);
49
+ if (t1.name.value !== t2.name.value) {
50
+ throw new Error(`Field "${b.name.value}" already defined with a different type. Declared as "${t1.name.value}", but you tried to override with "${t2.name.value}"`);
51
+ }
52
+ if (!safeChangeForFieldType(a.type, b.type, !ignoreNullability)) {
53
+ throw new Error(`Field '${type.name.value}.${a.name.value}' changed type from '${aType}' to '${bType}'`);
54
+ }
55
+ }
56
+ if ((0, utils_js_1.isNonNullTypeNode)(b.type) && !(0, utils_js_1.isNonNullTypeNode)(a.type)) {
57
+ a.type = b.type;
63
58
  }
59
+ return a;
64
60
  }
65
61
  function safeChangeForFieldType(oldType, newType, ignoreNullability = false) {
66
62
  // both are named
@@ -1,17 +1,20 @@
1
1
  import { compareNodes, isSome } from '@graphql-tools/utils';
2
2
  export function mergeArguments(args1, args2, config) {
3
- const result = deduplicateArguments([...args2, ...args1].filter(isSome));
3
+ const result = deduplicateArguments([...args2, ...args1].filter(isSome), config);
4
4
  if (config && config.sort) {
5
5
  result.sort(compareNodes);
6
6
  }
7
7
  return result;
8
8
  }
9
- function deduplicateArguments(args) {
9
+ function deduplicateArguments(args, config) {
10
10
  return args.reduce((acc, current) => {
11
- const dup = acc.find(arg => arg.name.value === current.name.value);
12
- if (!dup) {
11
+ const dupIndex = acc.findIndex(arg => arg.name.value === current.name.value);
12
+ if (dupIndex === -1) {
13
13
  return acc.concat([current]);
14
14
  }
15
+ else if (!(config === null || config === void 0 ? void 0 : config.reverseArguments)) {
16
+ acc[dupIndex] = current;
17
+ }
15
18
  return acc;
16
19
  }, []);
17
20
  }
@@ -2,16 +2,9 @@ import { extractType, isWrappingTypeNode, isListTypeNode, isNonNullTypeNode, pri
2
2
  import { mergeDirectives } from './directives.js';
3
3
  import { compareNodes } from '@graphql-tools/utils';
4
4
  import { mergeArguments } from './arguments.js';
5
- function fieldAlreadyExists(fieldsArr, otherField, config) {
6
- const result = fieldsArr.find(field => field.name.value === otherField.name.value);
7
- if (result && !(config === null || config === void 0 ? void 0 : config.ignoreFieldConflicts)) {
8
- const t1 = extractType(result.type);
9
- const t2 = extractType(otherField.type);
10
- if (t1.name.value !== t2.name.value) {
11
- throw new Error(`Field "${otherField.name.value}" already defined with a different type. Declared as "${t1.name.value}", but you tried to override with "${t2.name.value}"`);
12
- }
13
- }
14
- return !!result;
5
+ function fieldAlreadyExists(fieldsArr, otherField) {
6
+ const resultIndex = fieldsArr.findIndex(field => field.name.value === otherField.name.value);
7
+ return [resultIndex > -1 ? fieldsArr[resultIndex] : null, resultIndex];
15
8
  }
16
9
  export function mergeFields(type, f1, f2, config) {
17
10
  const result = [];
@@ -20,22 +13,14 @@ export function mergeFields(type, f1, f2, config) {
20
13
  }
21
14
  if (f1 != null) {
22
15
  for (const field of f1) {
23
- if (fieldAlreadyExists(result, field, config)) {
24
- const existing = result.find((f) => f.name.value === field.name.value);
25
- if (!(config === null || config === void 0 ? void 0 : config.ignoreFieldConflicts)) {
26
- if (config === null || config === void 0 ? void 0 : config.throwOnConflict) {
27
- preventConflicts(type, existing, field, false);
28
- }
29
- else {
30
- preventConflicts(type, existing, field, true);
31
- }
32
- if (isNonNullTypeNode(field.type) && !isNonNullTypeNode(existing.type)) {
33
- existing.type = field.type;
34
- }
35
- }
36
- existing.arguments = mergeArguments(field['arguments'] || [], existing.arguments || [], config);
37
- existing.directives = mergeDirectives(field.directives, existing.directives, config);
38
- existing.description = field.description || existing.description;
16
+ const [existing, existingIndex] = fieldAlreadyExists(result, field);
17
+ if (existing && !(config === null || config === void 0 ? void 0 : config.ignoreFieldConflicts)) {
18
+ const newField = ((config === null || config === void 0 ? void 0 : config.onFieldTypeConflict) && config.onFieldTypeConflict(existing, field, type, config === null || config === void 0 ? void 0 : config.throwOnConflict)) ||
19
+ preventConflicts(type, existing, field, config === null || config === void 0 ? void 0 : config.throwOnConflict);
20
+ newField.arguments = mergeArguments(field['arguments'] || [], existing['arguments'] || [], config);
21
+ newField.directives = mergeDirectives(field.directives, existing.directives, config);
22
+ newField.description = field.description || existing.description;
23
+ result[existingIndex] = newField;
39
24
  }
40
25
  else {
41
26
  result.push(field);
@@ -54,9 +39,20 @@ export function mergeFields(type, f1, f2, config) {
54
39
  function preventConflicts(type, a, b, ignoreNullability = false) {
55
40
  const aType = printTypeNode(a.type);
56
41
  const bType = printTypeNode(b.type);
57
- if (aType !== bType && !safeChangeForFieldType(a.type, b.type, ignoreNullability)) {
58
- throw new Error(`Field '${type.name.value}.${a.name.value}' changed type from '${aType}' to '${bType}'`);
42
+ if (aType !== bType) {
43
+ const t1 = extractType(a.type);
44
+ const t2 = extractType(b.type);
45
+ if (t1.name.value !== t2.name.value) {
46
+ throw new Error(`Field "${b.name.value}" already defined with a different type. Declared as "${t1.name.value}", but you tried to override with "${t2.name.value}"`);
47
+ }
48
+ if (!safeChangeForFieldType(a.type, b.type, !ignoreNullability)) {
49
+ throw new Error(`Field '${type.name.value}.${a.name.value}' changed type from '${aType}' to '${bType}'`);
50
+ }
51
+ }
52
+ if (isNonNullTypeNode(b.type) && !isNonNullTypeNode(a.type)) {
53
+ a.type = b.type;
59
54
  }
55
+ return a;
60
56
  }
61
57
  function safeChangeForFieldType(oldType, newType, ignoreNullability = false) {
62
58
  // both are named
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-tools/merge",
3
- "version": "8.3.18",
3
+ "version": "8.4.0-alpha-20230301043849-3d59d581",
4
4
  "description": "A set of utils for faster development of GraphQL tools",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -1,5 +1,11 @@
1
1
  import { Config } from './merge-typedefs.cjs';
2
2
  import { FieldDefinitionNode, InputValueDefinitionNode, NameNode } from 'graphql';
3
- export declare function mergeFields<T extends FieldDefinitionNode | InputValueDefinitionNode>(type: {
3
+ type FieldDefNode = FieldDefinitionNode | InputValueDefinitionNode;
4
+ type NamedDefNode = {
5
+ name: NameNode;
6
+ };
7
+ export type OnFieldTypeConflict = (existingField: FieldDefNode, otherField: FieldDefNode, type: NamedDefNode, ignoreNullability: boolean | undefined) => FieldDefNode;
8
+ export declare function mergeFields<T extends FieldDefNode>(type: {
4
9
  name: NameNode;
5
10
  }, f1: ReadonlyArray<T> | undefined, f2: ReadonlyArray<T> | undefined, config?: Config): T[];
11
+ export {};
@@ -1,5 +1,11 @@
1
1
  import { Config } from './merge-typedefs.js';
2
2
  import { FieldDefinitionNode, InputValueDefinitionNode, NameNode } from 'graphql';
3
- export declare function mergeFields<T extends FieldDefinitionNode | InputValueDefinitionNode>(type: {
3
+ type FieldDefNode = FieldDefinitionNode | InputValueDefinitionNode;
4
+ type NamedDefNode = {
5
+ name: NameNode;
6
+ };
7
+ export type OnFieldTypeConflict = (existingField: FieldDefNode, otherField: FieldDefNode, type: NamedDefNode, ignoreNullability: boolean | undefined) => FieldDefNode;
8
+ export declare function mergeFields<T extends FieldDefNode>(type: {
4
9
  name: NameNode;
5
10
  }, f1: ReadonlyArray<T> | undefined, f2: ReadonlyArray<T> | undefined, config?: Config): T[];
11
+ export {};
@@ -1,6 +1,7 @@
1
1
  import { DefinitionNode, DocumentNode, ParseOptions } from 'graphql';
2
2
  import { CompareFn } from './utils.cjs';
3
3
  import { GetDocumentNodeFromSchemaOptions, TypeSource } from '@graphql-tools/utils';
4
+ import { OnFieldTypeConflict } from './fields.cjs';
4
5
  type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
5
6
  export interface Config extends ParseOptions, GetDocumentNodeFromSchemaOptions {
6
7
  /**
@@ -54,6 +55,23 @@ export interface Config extends ParseOptions, GetDocumentNodeFromSchemaOptions {
54
55
  convertExtensions?: boolean;
55
56
  consistentEnumMerge?: boolean;
56
57
  ignoreFieldConflicts?: boolean;
58
+ /**
59
+ * Called if types of the same fields are different
60
+ *
61
+ * Default: false
62
+ *
63
+ * @example:
64
+ * Given:
65
+ * ```graphql
66
+ * type User { a: String }
67
+ * type User { a: Int }
68
+ * ```
69
+ *
70
+ * Instead of throwing `already defined with a different type` error,
71
+ * `onFieldTypeConflict` function is called.
72
+ */
73
+ onFieldTypeConflict?: OnFieldTypeConflict;
74
+ reverseArguments?: boolean;
57
75
  }
58
76
  /**
59
77
  * Merges multiple type definitions into a single `DocumentNode`
@@ -1,6 +1,7 @@
1
1
  import { DefinitionNode, DocumentNode, ParseOptions } from 'graphql';
2
2
  import { CompareFn } from './utils.js';
3
3
  import { GetDocumentNodeFromSchemaOptions, TypeSource } from '@graphql-tools/utils';
4
+ import { OnFieldTypeConflict } from './fields.js';
4
5
  type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
5
6
  export interface Config extends ParseOptions, GetDocumentNodeFromSchemaOptions {
6
7
  /**
@@ -54,6 +55,23 @@ export interface Config extends ParseOptions, GetDocumentNodeFromSchemaOptions {
54
55
  convertExtensions?: boolean;
55
56
  consistentEnumMerge?: boolean;
56
57
  ignoreFieldConflicts?: boolean;
58
+ /**
59
+ * Called if types of the same fields are different
60
+ *
61
+ * Default: false
62
+ *
63
+ * @example:
64
+ * Given:
65
+ * ```graphql
66
+ * type User { a: String }
67
+ * type User { a: Int }
68
+ * ```
69
+ *
70
+ * Instead of throwing `already defined with a different type` error,
71
+ * `onFieldTypeConflict` function is called.
72
+ */
73
+ onFieldTypeConflict?: OnFieldTypeConflict;
74
+ reverseArguments?: boolean;
57
75
  }
58
76
  /**
59
77
  * Merges multiple type definitions into a single `DocumentNode`