@equinor/cpl-utils 0.2.0 → 0.2.1

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/dist/index.d.mts CHANGED
@@ -113,6 +113,67 @@ declare function hasCircularDependency<T extends object>(items: T[], idKey: keyo
113
113
  */
114
114
  declare function itemIsDefined<T>(item: T): item is Exclude<typeof item, undefined>;
115
115
 
116
+ type NestedRecord<K extends readonly string[]> = K extends [
117
+ infer First extends string,
118
+ ...infer Rest extends string[]
119
+ ] ? Record<First, NestedRecord<Rest>> : unknown;
120
+ /**
121
+ * Checks if an object has a nested property chain, using Object.prototype.hasOwnProperty at each level.
122
+ * Returns true if all keys exist and are objects (except the last, which can be any value).
123
+ *
124
+ * @template K - Tuple of string keys representing the property chain.
125
+ * @param object - The object to check.
126
+ * @param keys - The property chain to check for.
127
+ * @returns {boolean} True if the nested property exists, false otherwise.
128
+ *
129
+ * @example
130
+ * // Basic usage
131
+ * const apiError = { error: { message: 'Not found' } }
132
+ * if (
133
+ * objectHasOwnNestedProperty(apiError, 'error', 'message') &&
134
+ * typeof apiError.error.message === 'string'
135
+ * ) {
136
+ * return apiError.error.message
137
+ * }
138
+ *
139
+ * @example
140
+ * // Deeply nested object
141
+ * const data = { a: { b: { c: 42 } } }
142
+ * if (objectHasOwnNestedProperty(data, 'a', 'b', 'c')) {
143
+ * console.log(data.a.b.c) // 42
144
+ * }
145
+ *
146
+
147
+ * @example
148
+ * // Usage in a try/catch block to extract a deeply nested error message
149
+ * try {
150
+ * // ...some code that may throw
151
+ * } catch(error) {
152
+ * if (
153
+ * objectHasOwnNestedProperty(error, 'body', 'error', 'message') &&
154
+ * typeof error.body.error.message === 'string'
155
+ * ) {
156
+ * setErrorMessage(error.body.error.message)
157
+ * }
158
+ * }
159
+ *
160
+ * // Missing property
161
+ * const obj = { a: { b: {} } }
162
+ * objectHasOwnNestedProperty(obj, 'a', 'b', 'c') // false
163
+ *
164
+ * @example
165
+ * // Works with arrays as values
166
+ * const arrObj = { a: { b: [1, 2, 3] } }
167
+ * objectHasOwnNestedProperty(arrObj, 'a', 'b') // true
168
+ *
169
+ * @example
170
+ * // TypeScript type guard
171
+ * if (objectHasOwnNestedProperty(apiError, 'error', 'message')) {
172
+ * // apiError is now typed as { error: { message: unknown } }
173
+ * }
174
+ */
175
+ declare function objectHasOwnNestedProperty<K extends readonly string[]>(object: unknown, ...keys: K): object is NestedRecord<K>;
176
+
116
177
  /**
117
178
  * A better typed `Object.prototype.objectHasOwnOroperty`. It helps TypeScript
118
179
  * infer types when an object has multiple types with different properties.
@@ -144,4 +205,4 @@ declare function itemIsDefined<T>(item: T): item is Exclude<typeof item, undefin
144
205
  */
145
206
  declare function objectHasOwnProperty<Key extends PropertyKey>(object: object, key: Key): object is Record<Key, unknown>;
146
207
 
147
- export { type TreeNode, buildTreeNodes, hasCircularDependency, itemIsDefined, objectHasOwnProperty };
208
+ export { type TreeNode, buildTreeNodes, hasCircularDependency, itemIsDefined, objectHasOwnNestedProperty, objectHasOwnProperty };
package/dist/index.d.ts CHANGED
@@ -113,6 +113,67 @@ declare function hasCircularDependency<T extends object>(items: T[], idKey: keyo
113
113
  */
114
114
  declare function itemIsDefined<T>(item: T): item is Exclude<typeof item, undefined>;
115
115
 
116
+ type NestedRecord<K extends readonly string[]> = K extends [
117
+ infer First extends string,
118
+ ...infer Rest extends string[]
119
+ ] ? Record<First, NestedRecord<Rest>> : unknown;
120
+ /**
121
+ * Checks if an object has a nested property chain, using Object.prototype.hasOwnProperty at each level.
122
+ * Returns true if all keys exist and are objects (except the last, which can be any value).
123
+ *
124
+ * @template K - Tuple of string keys representing the property chain.
125
+ * @param object - The object to check.
126
+ * @param keys - The property chain to check for.
127
+ * @returns {boolean} True if the nested property exists, false otherwise.
128
+ *
129
+ * @example
130
+ * // Basic usage
131
+ * const apiError = { error: { message: 'Not found' } }
132
+ * if (
133
+ * objectHasOwnNestedProperty(apiError, 'error', 'message') &&
134
+ * typeof apiError.error.message === 'string'
135
+ * ) {
136
+ * return apiError.error.message
137
+ * }
138
+ *
139
+ * @example
140
+ * // Deeply nested object
141
+ * const data = { a: { b: { c: 42 } } }
142
+ * if (objectHasOwnNestedProperty(data, 'a', 'b', 'c')) {
143
+ * console.log(data.a.b.c) // 42
144
+ * }
145
+ *
146
+
147
+ * @example
148
+ * // Usage in a try/catch block to extract a deeply nested error message
149
+ * try {
150
+ * // ...some code that may throw
151
+ * } catch(error) {
152
+ * if (
153
+ * objectHasOwnNestedProperty(error, 'body', 'error', 'message') &&
154
+ * typeof error.body.error.message === 'string'
155
+ * ) {
156
+ * setErrorMessage(error.body.error.message)
157
+ * }
158
+ * }
159
+ *
160
+ * // Missing property
161
+ * const obj = { a: { b: {} } }
162
+ * objectHasOwnNestedProperty(obj, 'a', 'b', 'c') // false
163
+ *
164
+ * @example
165
+ * // Works with arrays as values
166
+ * const arrObj = { a: { b: [1, 2, 3] } }
167
+ * objectHasOwnNestedProperty(arrObj, 'a', 'b') // true
168
+ *
169
+ * @example
170
+ * // TypeScript type guard
171
+ * if (objectHasOwnNestedProperty(apiError, 'error', 'message')) {
172
+ * // apiError is now typed as { error: { message: unknown } }
173
+ * }
174
+ */
175
+ declare function objectHasOwnNestedProperty<K extends readonly string[]>(object: unknown, ...keys: K): object is NestedRecord<K>;
176
+
116
177
  /**
117
178
  * A better typed `Object.prototype.objectHasOwnOroperty`. It helps TypeScript
118
179
  * infer types when an object has multiple types with different properties.
@@ -144,4 +205,4 @@ declare function itemIsDefined<T>(item: T): item is Exclude<typeof item, undefin
144
205
  */
145
206
  declare function objectHasOwnProperty<Key extends PropertyKey>(object: object, key: Key): object is Record<Key, unknown>;
146
207
 
147
- export { type TreeNode, buildTreeNodes, hasCircularDependency, itemIsDefined, objectHasOwnProperty };
208
+ export { type TreeNode, buildTreeNodes, hasCircularDependency, itemIsDefined, objectHasOwnNestedProperty, objectHasOwnProperty };
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  buildTreeNodes: () => buildTreeNodes,
24
24
  hasCircularDependency: () => hasCircularDependency,
25
25
  itemIsDefined: () => itemIsDefined,
26
+ objectHasOwnNestedProperty: () => objectHasOwnNestedProperty,
26
27
  objectHasOwnProperty: () => objectHasOwnProperty
27
28
  });
28
29
  module.exports = __toCommonJS(index_exports);
@@ -107,10 +108,26 @@ function buildTreeNodes(items, idKey, parentIdKey, options = {}) {
107
108
  function itemIsDefined(item) {
108
109
  return item !== void 0;
109
110
  }
111
+
112
+ // src/object-has-own-nested-property.ts
113
+ function objectHasOwnNestedProperty(object, ...keys) {
114
+ if (typeof object !== "object" || object === null) {
115
+ return false;
116
+ }
117
+ let currentObject = object;
118
+ for (const key of keys) {
119
+ if (!objectHasOwnProperty(currentObject, key) || typeof currentObject[key] !== "object" || currentObject[key] === null) {
120
+ return false;
121
+ }
122
+ currentObject = currentObject[key];
123
+ }
124
+ return true;
125
+ }
110
126
  // Annotate the CommonJS export names for ESM import in node:
111
127
  0 && (module.exports = {
112
128
  buildTreeNodes,
113
129
  hasCircularDependency,
114
130
  itemIsDefined,
131
+ objectHasOwnNestedProperty,
115
132
  objectHasOwnProperty
116
133
  });
package/dist/index.mjs CHANGED
@@ -78,9 +78,25 @@ function buildTreeNodes(items, idKey, parentIdKey, options = {}) {
78
78
  function itemIsDefined(item) {
79
79
  return item !== void 0;
80
80
  }
81
+
82
+ // src/object-has-own-nested-property.ts
83
+ function objectHasOwnNestedProperty(object, ...keys) {
84
+ if (typeof object !== "object" || object === null) {
85
+ return false;
86
+ }
87
+ let currentObject = object;
88
+ for (const key of keys) {
89
+ if (!objectHasOwnProperty(currentObject, key) || typeof currentObject[key] !== "object" || currentObject[key] === null) {
90
+ return false;
91
+ }
92
+ currentObject = currentObject[key];
93
+ }
94
+ return true;
95
+ }
81
96
  export {
82
97
  buildTreeNodes,
83
98
  hasCircularDependency,
84
99
  itemIsDefined,
100
+ objectHasOwnNestedProperty,
85
101
  objectHasOwnProperty
86
102
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/cpl-utils",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",