@graphql-tools/utils 12.0.1 → 12.0.3

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.
package/cjs/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createDeferred = exports.fakePromise = exports.mapMaybePromise = exports.mapAsyncIterator = exports.inspect = void 0;
3
+ exports.createDeferred = exports.fakePromise = exports.mapAsyncIterator = exports.mapMaybePromise = exports.inspect = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  tslib_1.__exportStar(require("./loaders.js"), exports);
6
6
  tslib_1.__exportStar(require("./helpers.js"), exports);
@@ -60,9 +60,10 @@ tslib_1.__exportStar(require("./directives.js"), exports);
60
60
  tslib_1.__exportStar(require("./mergeIncrementalResult.js"), exports);
61
61
  tslib_1.__exportStar(require("./debugTimer.js"), exports);
62
62
  tslib_1.__exportStar(require("./getDirectiveExtensions.js"), exports);
63
+ var jsutils_js_1 = require("./jsutils.js");
64
+ Object.defineProperty(exports, "mapMaybePromise", { enumerable: true, get: function () { return jsutils_js_1.mapMaybePromise; } });
63
65
  var promise_helpers_1 = require("@whatwg-node/promise-helpers");
64
66
  Object.defineProperty(exports, "mapAsyncIterator", { enumerable: true, get: function () { return promise_helpers_1.mapAsyncIterator; } });
65
- Object.defineProperty(exports, "mapMaybePromise", { enumerable: true, get: function () { return promise_helpers_1.mapMaybePromise; } });
66
67
  Object.defineProperty(exports, "fakePromise", { enumerable: true, get: function () { return promise_helpers_1.fakePromise; } });
67
68
  Object.defineProperty(exports, "createDeferred", { enumerable: true, get: function () { return promise_helpers_1.createDeferredPromise; } });
68
69
  tslib_1.__exportStar(require("./registerAbortSignalListener.js"), exports);
package/cjs/jsutils.js CHANGED
@@ -3,8 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isPromise = void 0;
4
4
  exports.isIterableObject = isIterableObject;
5
5
  exports.isObjectLike = isObjectLike;
6
+ exports.mapMaybePromise = mapMaybePromise;
6
7
  exports.promiseReduce = promiseReduce;
7
8
  exports.hasOwnProperty = hasOwnProperty;
9
+ exports.isDangerousObjectKey = isDangerousObjectKey;
10
+ exports.isSafeObjectKey = isSafeObjectKey;
8
11
  const promise_helpers_1 = require("@whatwg-node/promise-helpers");
9
12
  Object.defineProperty(exports, "isPromise", { enumerable: true, get: function () { return promise_helpers_1.isPromise; } });
10
13
  function isIterableObject(value) {
@@ -13,6 +16,9 @@ function isIterableObject(value) {
13
16
  function isObjectLike(value) {
14
17
  return typeof value === 'object' && value !== null;
15
18
  }
19
+ function mapMaybePromise(input, onSuccess, onError) {
20
+ return (0, promise_helpers_1.handleMaybePromise)(() => input, onSuccess, onError);
21
+ }
16
22
  function promiseReduce(values, callbackFn, initialValue) {
17
23
  let accumulator = initialValue;
18
24
  for (const value of values) {
@@ -23,3 +29,21 @@ function promiseReduce(values, callbackFn, initialValue) {
23
29
  function hasOwnProperty(obj, prop) {
24
30
  return Object.prototype.hasOwnProperty.call(obj, prop);
25
31
  }
32
+ /**
33
+ * True for keys that must never be used for object-path writes because they
34
+ * reach the prototype chain (`__proto__`, `constructor`, `prototype`).
35
+ */
36
+ function isDangerousObjectKey(key) {
37
+ return key === '__proto__' || key === 'constructor' || key === 'prototype';
38
+ }
39
+ /**
40
+ * True when `key` is a primitive string/number that is safe to use for
41
+ * own-property access. Rejects non-primitives (which coerce via `ToPropertyKey`)
42
+ * and {@link isDangerousObjectKey dangerous names}.
43
+ */
44
+ function isSafeObjectKey(key) {
45
+ if (typeof key !== 'string' && typeof key !== 'number') {
46
+ return false;
47
+ }
48
+ return !isDangerousObjectKey(key);
49
+ }
package/cjs/mergeDeep.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.mergeDeep = mergeDeep;
4
4
  const helpers_js_1 = require("./helpers.js");
5
+ const jsutils_js_1 = require("./jsutils.js");
5
6
  function mergeDeep(sources, respectPrototype = false, respectArrays = false, respectArrayLength = false, respectNonEnumerableSymbols = false) {
6
7
  if (sources.length === 0) {
7
8
  return;
@@ -65,7 +66,7 @@ function mergeDeep(sources, respectPrototype = false, respectArrays = false, res
65
66
  }
66
67
  for (const key in source) {
67
68
  // never let a source key reach the prototype chain
68
- if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
69
+ if ((0, jsutils_js_1.isDangerousObjectKey)(key)) {
69
70
  continue;
70
71
  }
71
72
  // An own key present with value `undefined` is an explicit override and must win,
@@ -1,14 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.mergeIncrementalResult = mergeIncrementalResult;
4
+ const jsutils_js_1 = require("./jsutils.js");
4
5
  const mergeDeep_js_1 = require("./mergeDeep.js");
5
6
  function mergeIncrementalResult({ incrementalResult, executionResult, }) {
6
7
  const path = ['data', ...(incrementalResult.path ?? [])];
7
8
  if (incrementalResult.items) {
8
- for (const item of incrementalResult.items) {
9
- setObjectKeyPath(executionResult, path, item);
10
- // Increment the last path segment (the array index) to merge the next item at the next index
11
- path[path.length - 1]++;
9
+ // Reject the whole items batch if any path segment is unsafe, so a later
10
+ // index increment cannot turn a bad segment into a write at `data.NaN`.
11
+ if (isSafeKeyPath(path)) {
12
+ for (const item of incrementalResult.items) {
13
+ setObjectKeyPath(executionResult, path, item);
14
+ // Increment the last path segment (the array index) to merge the next item at the next index
15
+ path[path.length - 1]++;
16
+ }
12
17
  }
13
18
  }
14
19
  if (incrementalResult.data) {
@@ -30,24 +35,34 @@ function mergeIncrementalResult({ incrementalResult, executionResult, }) {
30
35
  });
31
36
  }
32
37
  }
38
+ function isSafeKeyPath(keyPath) {
39
+ return keyPath.every(jsutils_js_1.isSafeObjectKey);
40
+ }
33
41
  function setObjectKeyPath(obj, keyPath, value) {
42
+ // Validate the full path before creating any parent containers, so a late
43
+ // unsafe segment cannot leave partial writes on executionResult.
44
+ if (!isSafeKeyPath(keyPath)) {
45
+ return;
46
+ }
34
47
  let current = obj;
35
48
  let i;
36
49
  for (i = 0; i < keyPath.length - 1; i++) {
37
50
  const key = keyPath[i];
38
- if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
51
+ // Direct comparison, not only isSafeObjectKey(): that helper already rejects
52
+ // this key, but the check has to sit on the value used as the property name.
53
+ if (key === '__proto__' || !(0, jsutils_js_1.isSafeObjectKey)(key)) {
39
54
  return;
40
55
  }
41
- if (current[key] == null) {
56
+ if (!(0, jsutils_js_1.hasOwnProperty)(current, key) || current[key] == null) {
42
57
  // Determine if the next key is a number to create an array, otherwise create an object
43
58
  current[key] = typeof keyPath[i + 1] === 'number' ? [] : {};
44
59
  }
45
60
  current = current[key];
46
61
  }
47
62
  const finalKey = keyPath[i];
48
- if (finalKey === '__proto__' || finalKey === 'constructor' || finalKey === 'prototype') {
63
+ if (finalKey === '__proto__' || !(0, jsutils_js_1.isSafeObjectKey)(finalKey)) {
49
64
  return;
50
65
  }
51
- const existingValue = current[finalKey];
66
+ const existingValue = (0, jsutils_js_1.hasOwnProperty)(current, finalKey) ? current[finalKey] : undefined;
52
67
  current[finalKey] = existingValue != null ? (0, mergeDeep_js_1.mergeDeep)([existingValue, value]) : value;
53
68
  }
package/esm/index.js CHANGED
@@ -55,6 +55,7 @@ export * from './directives.js';
55
55
  export * from './mergeIncrementalResult.js';
56
56
  export * from './debugTimer.js';
57
57
  export * from './getDirectiveExtensions.js';
58
- export { mapAsyncIterator, mapMaybePromise, fakePromise, createDeferredPromise as createDeferred, } from '@whatwg-node/promise-helpers';
58
+ export { mapMaybePromise } from './jsutils.js';
59
+ export { mapAsyncIterator, fakePromise, createDeferredPromise as createDeferred, } from '@whatwg-node/promise-helpers';
59
60
  export * from './registerAbortSignalListener.js';
60
61
  export * from './getDirectiveValues.js';
package/esm/jsutils.js CHANGED
@@ -6,6 +6,9 @@ export function isObjectLike(value) {
6
6
  return typeof value === 'object' && value !== null;
7
7
  }
8
8
  export { isPromise };
9
+ export function mapMaybePromise(input, onSuccess, onError) {
10
+ return handleMaybePromise(() => input, onSuccess, onError);
11
+ }
9
12
  export function promiseReduce(values, callbackFn, initialValue) {
10
13
  let accumulator = initialValue;
11
14
  for (const value of values) {
@@ -16,3 +19,21 @@ export function promiseReduce(values, callbackFn, initialValue) {
16
19
  export function hasOwnProperty(obj, prop) {
17
20
  return Object.prototype.hasOwnProperty.call(obj, prop);
18
21
  }
22
+ /**
23
+ * True for keys that must never be used for object-path writes because they
24
+ * reach the prototype chain (`__proto__`, `constructor`, `prototype`).
25
+ */
26
+ export function isDangerousObjectKey(key) {
27
+ return key === '__proto__' || key === 'constructor' || key === 'prototype';
28
+ }
29
+ /**
30
+ * True when `key` is a primitive string/number that is safe to use for
31
+ * own-property access. Rejects non-primitives (which coerce via `ToPropertyKey`)
32
+ * and {@link isDangerousObjectKey dangerous names}.
33
+ */
34
+ export function isSafeObjectKey(key) {
35
+ if (typeof key !== 'string' && typeof key !== 'number') {
36
+ return false;
37
+ }
38
+ return !isDangerousObjectKey(key);
39
+ }
package/esm/mergeDeep.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { isSome } from './helpers.js';
2
+ import { isDangerousObjectKey } from './jsutils.js';
2
3
  export function mergeDeep(sources, respectPrototype = false, respectArrays = false, respectArrayLength = false, respectNonEnumerableSymbols = false) {
3
4
  if (sources.length === 0) {
4
5
  return;
@@ -62,7 +63,7 @@ export function mergeDeep(sources, respectPrototype = false, respectArrays = fal
62
63
  }
63
64
  for (const key in source) {
64
65
  // never let a source key reach the prototype chain
65
- if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
66
+ if (isDangerousObjectKey(key)) {
66
67
  continue;
67
68
  }
68
69
  // An own key present with value `undefined` is an explicit override and must win,
@@ -1,11 +1,16 @@
1
+ import { hasOwnProperty, isSafeObjectKey } from './jsutils.js';
1
2
  import { mergeDeep } from './mergeDeep.js';
2
3
  export function mergeIncrementalResult({ incrementalResult, executionResult, }) {
3
4
  const path = ['data', ...(incrementalResult.path ?? [])];
4
5
  if (incrementalResult.items) {
5
- for (const item of incrementalResult.items) {
6
- setObjectKeyPath(executionResult, path, item);
7
- // Increment the last path segment (the array index) to merge the next item at the next index
8
- path[path.length - 1]++;
6
+ // Reject the whole items batch if any path segment is unsafe, so a later
7
+ // index increment cannot turn a bad segment into a write at `data.NaN`.
8
+ if (isSafeKeyPath(path)) {
9
+ for (const item of incrementalResult.items) {
10
+ setObjectKeyPath(executionResult, path, item);
11
+ // Increment the last path segment (the array index) to merge the next item at the next index
12
+ path[path.length - 1]++;
13
+ }
9
14
  }
10
15
  }
11
16
  if (incrementalResult.data) {
@@ -27,24 +32,34 @@ export function mergeIncrementalResult({ incrementalResult, executionResult, })
27
32
  });
28
33
  }
29
34
  }
35
+ function isSafeKeyPath(keyPath) {
36
+ return keyPath.every(isSafeObjectKey);
37
+ }
30
38
  function setObjectKeyPath(obj, keyPath, value) {
39
+ // Validate the full path before creating any parent containers, so a late
40
+ // unsafe segment cannot leave partial writes on executionResult.
41
+ if (!isSafeKeyPath(keyPath)) {
42
+ return;
43
+ }
31
44
  let current = obj;
32
45
  let i;
33
46
  for (i = 0; i < keyPath.length - 1; i++) {
34
47
  const key = keyPath[i];
35
- if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
48
+ // Direct comparison, not only isSafeObjectKey(): that helper already rejects
49
+ // this key, but the check has to sit on the value used as the property name.
50
+ if (key === '__proto__' || !isSafeObjectKey(key)) {
36
51
  return;
37
52
  }
38
- if (current[key] == null) {
53
+ if (!hasOwnProperty(current, key) || current[key] == null) {
39
54
  // Determine if the next key is a number to create an array, otherwise create an object
40
55
  current[key] = typeof keyPath[i + 1] === 'number' ? [] : {};
41
56
  }
42
57
  current = current[key];
43
58
  }
44
59
  const finalKey = keyPath[i];
45
- if (finalKey === '__proto__' || finalKey === 'constructor' || finalKey === 'prototype') {
60
+ if (finalKey === '__proto__' || !isSafeObjectKey(finalKey)) {
46
61
  return;
47
62
  }
48
- const existingValue = current[finalKey];
63
+ const existingValue = hasOwnProperty(current, finalKey) ? current[finalKey] : undefined;
49
64
  current[finalKey] = existingValue != null ? mergeDeep([existingValue, value]) : value;
50
65
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-tools/utils",
3
- "version": "12.0.1",
3
+ "version": "12.0.3",
4
4
  "description": "Common package containing utils and types for GraphQL tools",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "@graphql-typed-document-node/core": "^3.1.1",
11
- "@whatwg-node/promise-helpers": "^1.0.0",
11
+ "@whatwg-node/promise-helpers": "^2.0.0",
12
12
  "cross-inspect": "1.0.1",
13
13
  "tslib": "^2.4.0"
14
14
  },
@@ -55,6 +55,7 @@ export * from './directives.cjs';
55
55
  export * from './mergeIncrementalResult.cjs';
56
56
  export * from './debugTimer.cjs';
57
57
  export * from './getDirectiveExtensions.cjs';
58
- export { mapAsyncIterator, mapMaybePromise, fakePromise, createDeferredPromise as createDeferred, } from '@whatwg-node/promise-helpers';
58
+ export { mapMaybePromise } from './jsutils.cjs';
59
+ export { mapAsyncIterator, fakePromise, createDeferredPromise as createDeferred, } from '@whatwg-node/promise-helpers';
59
60
  export * from './registerAbortSignalListener.cjs';
60
61
  export * from './getDirectiveValues.cjs';
@@ -55,6 +55,7 @@ export * from './directives.js';
55
55
  export * from './mergeIncrementalResult.js';
56
56
  export * from './debugTimer.js';
57
57
  export * from './getDirectiveExtensions.js';
58
- export { mapAsyncIterator, mapMaybePromise, fakePromise, createDeferredPromise as createDeferred, } from '@whatwg-node/promise-helpers';
58
+ export { mapMaybePromise } from './jsutils.js';
59
+ export { mapAsyncIterator, fakePromise, createDeferredPromise as createDeferred, } from '@whatwg-node/promise-helpers';
59
60
  export * from './registerAbortSignalListener.js';
60
61
  export * from './getDirectiveValues.js';
@@ -4,5 +4,17 @@ export declare function isObjectLike(value: unknown): value is {
4
4
  [key: string]: unknown;
5
5
  };
6
6
  export { isPromise };
7
+ export declare function mapMaybePromise<TInput, TOutput>(input: MaybePromise<TInput>, onSuccess: (value: TInput) => MaybePromise<TOutput>, onError?: (err: any) => MaybePromise<TOutput>): MaybePromise<TOutput>;
7
8
  export declare function promiseReduce<T, U>(values: Iterable<T>, callbackFn: (accumulator: U, currentValue: T) => MaybePromise<U>, initialValue: MaybePromise<U>): MaybePromise<U>;
8
- export declare function hasOwnProperty(obj: unknown, prop: string): boolean;
9
+ export declare function hasOwnProperty(obj: unknown, prop: PropertyKey): boolean;
10
+ /**
11
+ * True for keys that must never be used for object-path writes because they
12
+ * reach the prototype chain (`__proto__`, `constructor`, `prototype`).
13
+ */
14
+ export declare function isDangerousObjectKey(key: unknown): boolean;
15
+ /**
16
+ * True when `key` is a primitive string/number that is safe to use for
17
+ * own-property access. Rejects non-primitives (which coerce via `ToPropertyKey`)
18
+ * and {@link isDangerousObjectKey dangerous names}.
19
+ */
20
+ export declare function isSafeObjectKey(key: unknown): key is string | number;
@@ -4,5 +4,17 @@ export declare function isObjectLike(value: unknown): value is {
4
4
  [key: string]: unknown;
5
5
  };
6
6
  export { isPromise };
7
+ export declare function mapMaybePromise<TInput, TOutput>(input: MaybePromise<TInput>, onSuccess: (value: TInput) => MaybePromise<TOutput>, onError?: (err: any) => MaybePromise<TOutput>): MaybePromise<TOutput>;
7
8
  export declare function promiseReduce<T, U>(values: Iterable<T>, callbackFn: (accumulator: U, currentValue: T) => MaybePromise<U>, initialValue: MaybePromise<U>): MaybePromise<U>;
8
- export declare function hasOwnProperty(obj: unknown, prop: string): boolean;
9
+ export declare function hasOwnProperty(obj: unknown, prop: PropertyKey): boolean;
10
+ /**
11
+ * True for keys that must never be used for object-path writes because they
12
+ * reach the prototype chain (`__proto__`, `constructor`, `prototype`).
13
+ */
14
+ export declare function isDangerousObjectKey(key: unknown): boolean;
15
+ /**
16
+ * True when `key` is a primitive string/number that is safe to use for
17
+ * own-property access. Rejects non-primitives (which coerce via `ToPropertyKey`)
18
+ * and {@link isDangerousObjectKey dangerous names}.
19
+ */
20
+ export declare function isSafeObjectKey(key: unknown): key is string | number;