@thi.ng/resolve-map 6.0.1 → 6.1.2

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/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2022-05-07T11:33:35Z
3
+ - **Last updated**: 2022-06-09T16:14:01Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,16 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ ## [6.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/resolve-map@6.1.0) (2022-05-23)
13
+
14
+ #### 🚀 Features
15
+
16
+ - add support for protected values ([6280510](https://github.com/thi-ng/umbrella/commit/6280510))
17
+ - add `Resolved` wrapper & factory fn for protecting values from
18
+ future/duplicate resolution attempts
19
+ - add tests
20
+ - update docs/readme
21
+
12
22
  # [6.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/resolve-map@6.0.0) (2022-05-02)
13
23
 
14
24
  #### 🛑 Breaking changes
package/README.md CHANGED
@@ -19,6 +19,7 @@ This project is part of the
19
19
  - [Theme configuration](#theme-configuration)
20
20
  - [API](#api)
21
21
  - [`resolve(obj)`](#resolveobj)
22
+ - [Protecting values](#protecting-values)
22
23
  - [Authors](#authors)
23
24
  - [License](#license)
24
25
 
@@ -75,7 +76,7 @@ node --experimental-repl-await
75
76
  > const resolveMap = await import("@thi.ng/resolve-map");
76
77
  ```
77
78
 
78
- Package sizes (gzipped, pre-treeshake): ESM: 929 bytes
79
+ Package sizes (gzipped, pre-treeshake): ESM: 1.03 KB
79
80
 
80
81
  ## Dependencies
81
82
 
@@ -297,6 +298,15 @@ res.e(2);
297
298
  // 20
298
299
  ```
299
300
 
301
+ #### Protecting values
302
+
303
+ Values can be protected from further resolution attempts by wrapping them via
304
+ [`resolved()`](https://docs.thi.ng/umbrella/resolve-map/modules.html#resolved).
305
+ The wrapped value can be later obtained via the standard [`IDeref`
306
+ interface/mechanism](https://docs.thi.ng/umbrella/api/interfaces/IDeref.html).
307
+ In lookup/resolution functions, the unwrapped value will be supplied, no
308
+ `.deref()` necessary there.
309
+
300
310
  ## Authors
301
311
 
302
312
  Karsten Schmidt
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { Fn, NumOrString } from "@thi.ng/api";
1
+ import type { Fn, IDeref, NumOrString } from "@thi.ng/api";
2
2
  export declare type Unresolved<T> = {
3
- [K in keyof T]: Unresolved<T[K]> | Fn<T, T[K]> | Fn<ResolveFn, T[K]> | Function | string;
3
+ [K in keyof T]: Unresolved<T[K]> | Resolved<T[K]> | Fn<T, T[K]> | Fn<ResolveFn, T[K]> | Function | string;
4
4
  };
5
5
  export declare type ResolveFn = (path: string) => any;
6
6
  export declare type LookupPath = NumOrString[];
@@ -19,6 +19,11 @@ export declare type LookupPath = NumOrString[];
19
19
  * access any parent levels. Absolute refs are always resolved from the root
20
20
  * level (the original object passed to this function).
21
21
  *
22
+ * Values can be protected from further resolution attempts by wrapping them via
23
+ * {@link resolved}. The wrapped value can be later obtained via the standard
24
+ * {@link @thi.ng/api#IDeref} interface/mechanism. In lookup functions, the
25
+ * unwrapped value will be supplied, no `.deref()` necessary there.
26
+ *
22
27
  * @example
23
28
  * ```ts
24
29
  * // `c` references sibling `d`
@@ -96,4 +101,22 @@ export declare function resolve<T>(root: Unresolved<T[]>, prefix?: string): T[];
96
101
  * @param idx -
97
102
  */
98
103
  export declare const absPath: (curr: LookupPath, path: string, idx?: number) => NumOrString[];
104
+ /**
105
+ * Value wrapper to protect from future recursive resolution attempts. See
106
+ * {@link resolved} for further details.
107
+ */
108
+ export declare class Resolved<T> implements IDeref<T> {
109
+ protected _value: T;
110
+ constructor(_value: T);
111
+ deref(): T;
112
+ }
113
+ /**
114
+ * Factory function for {@link Resolved} to wrap & protect values from further
115
+ * resolution attempts. The wrapped value can be later obtained via the standard
116
+ * {@link @thi.ng/api#IDeref} interface/mechanism. In lookup functions, the
117
+ * unwrapped value will be supplied, no `.deref()` necessary there.
118
+ *
119
+ * @param val
120
+ */
121
+ export declare const resolved: <T>(val: T) => Resolved<T>;
99
122
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -4,7 +4,6 @@ import { isFunction } from "@thi.ng/checks/is-function";
4
4
  import { isPlainObject } from "@thi.ng/checks/is-plain-object";
5
5
  import { isString } from "@thi.ng/checks/is-string";
6
6
  import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
7
- import { getInUnsafe } from "@thi.ng/paths/get-in";
8
7
  import { mutInUnsafe } from "@thi.ng/paths/mut-in";
9
8
  import { exists } from "@thi.ng/paths/path";
10
9
  const RE_ARGS = /^(function\s+\w+)?\s*\(\{([\w\s,:]+)\}/;
@@ -48,8 +47,12 @@ const _resolve = (root, path, resolved, stack, prefix) => {
48
47
  illegalArgs(`cyclic references not allowed: ${pathID}`);
49
48
  }
50
49
  // console.log(pp, resolved[pp], stack);
51
- let v = getInUnsafe(root, path);
50
+ let [v, isResolved] = getInUnsafe(root, path);
52
51
  if (!resolved[pathID]) {
52
+ if (isResolved) {
53
+ resolved[pathID] = true;
54
+ return v;
55
+ }
53
56
  let res = SEMAPHORE;
54
57
  stack.push(pathID);
55
58
  if (isPlainObject(v)) {
@@ -190,3 +193,47 @@ export const absPath = (curr, path, idx = 1) => {
190
193
  !curr.length && illegalArgs(`invalid lookup path: ${path}`);
191
194
  return curr;
192
195
  };
196
+ /**
197
+ * Value wrapper to protect from future recursive resolution attempts. See
198
+ * {@link resolved} for further details.
199
+ */
200
+ export class Resolved {
201
+ constructor(_value) {
202
+ this._value = _value;
203
+ }
204
+ deref() {
205
+ return this._value;
206
+ }
207
+ }
208
+ /**
209
+ * Factory function for {@link Resolved} to wrap & protect values from further
210
+ * resolution attempts. The wrapped value can be later obtained via the standard
211
+ * {@link @thi.ng/api#IDeref} interface/mechanism. In lookup functions, the
212
+ * unwrapped value will be supplied, no `.deref()` necessary there.
213
+ *
214
+ * @param val
215
+ */
216
+ export const resolved = (val) => new Resolved(val);
217
+ /**
218
+ * Special version of {@link @thi.ng/paths#getInUnsafe} with extra support for
219
+ * intermediate wrapped {@link Resolved} values and returning tuple of:
220
+ * `[val,isResolved]`.
221
+ *
222
+ * @param obj
223
+ * @param path
224
+ *
225
+ * @internal
226
+ */
227
+ const getInUnsafe = (obj, path) => {
228
+ const n = path.length - 1;
229
+ let res = obj;
230
+ let isResolved = obj instanceof Resolved;
231
+ for (let i = 0; res != null && i <= n; i++) {
232
+ res = res[path[i]];
233
+ if (res instanceof Resolved) {
234
+ isResolved = true;
235
+ res = res.deref();
236
+ }
237
+ }
238
+ return [res, isResolved];
239
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/resolve-map",
3
- "version": "6.0.1",
3
+ "version": "6.1.2",
4
4
  "description": "DAG resolution of vanilla objects & arrays with internally linked values",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -34,18 +34,18 @@
34
34
  "test": "testament test"
35
35
  },
36
36
  "dependencies": {
37
- "@thi.ng/api": "^8.3.6",
38
- "@thi.ng/checks": "^3.1.6",
39
- "@thi.ng/errors": "^2.1.6",
40
- "@thi.ng/paths": "^5.1.6"
37
+ "@thi.ng/api": "^8.3.7",
38
+ "@thi.ng/checks": "^3.2.1",
39
+ "@thi.ng/errors": "^2.1.7",
40
+ "@thi.ng/paths": "^5.1.8"
41
41
  },
42
42
  "devDependencies": {
43
- "@microsoft/api-extractor": "^7.23.1",
44
- "@thi.ng/testament": "^0.2.6",
43
+ "@microsoft/api-extractor": "^7.25.0",
44
+ "@thi.ng/testament": "^0.2.8",
45
45
  "rimraf": "^3.0.2",
46
46
  "tools": "^0.0.1",
47
- "typedoc": "^0.22.15",
48
- "typescript": "^4.6.4"
47
+ "typedoc": "^0.22.17",
48
+ "typescript": "^4.7.3"
49
49
  },
50
50
  "keywords": [
51
51
  "configuration",
@@ -76,5 +76,5 @@
76
76
  ],
77
77
  "year": 2018
78
78
  },
79
- "gitHead": "cf084be5fd5932226054d2dd32bad35481379f5d\n"
79
+ "gitHead": "ab0188234419f2d9f471de80871df930e5555bd6\n"
80
80
  }