@web-ts-toolkit/access-router 0.44.0 → 0.46.0

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/processors.mjs CHANGED
@@ -1,23 +1,58 @@
1
1
  // src/processors.ts
2
- import { cloneDeep, forEach, get, isArray, isPlainObject, map, set } from "@web-ts-toolkit/utils";
2
+ import { cloneDeep, forEach, get, hasOwn, isArray, isPlainObject, map, set } from "@web-ts-toolkit/utils";
3
3
  var UNSAFE_PATH_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
4
- function failUnsafeSegment(path) {
4
+ var DEFAULT_MAX_SLICE = 1e3;
5
+ var DEFAULT_MASK_REPLACEMENT = "***";
6
+ function failUnsafeSegment(path, fn = "copyAndDepopulate") {
5
7
  throw new Error(
6
- `copyAndDepopulate: refusing path '${path}' because it contains an unsafe segment (__proto__, prototype, or constructor).`
8
+ `${fn}: refusing path '${path}' because it contains an unsafe segment (__proto__, prototype, or constructor).`
7
9
  );
8
10
  }
9
11
  function failMissingId(path) {
10
12
  throw new Error(`copyAndDepopulate: path '${path}' resolved to a record missing the configured id field.`);
11
13
  }
12
- function assertSafePath(path) {
14
+ function failInvalidSlice(value, field, fn) {
15
+ throw new Error(`${fn}: '${field}' must be a non-negative safe integer, received ${String(value)}.`);
16
+ }
17
+ function assertSafePath(path, fn = "copyAndDepopulate") {
13
18
  const segs = path.split(".");
14
19
  for (const seg of segs) {
15
20
  if (seg.length === 0) continue;
16
21
  if (UNSAFE_PATH_KEYS.has(seg)) {
17
- failUnsafeSegment(path);
22
+ failUnsafeSegment(path, fn);
18
23
  }
19
24
  }
20
25
  }
26
+ function assertNonNegativeSafeInteger(value, field, fn) {
27
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
28
+ failInvalidSlice(value, field, fn);
29
+ }
30
+ }
31
+ function resolveLeafParents(obj, src) {
32
+ const segs = src.split(".");
33
+ let targets = [obj];
34
+ for (let ind = 0; ind < segs.length - 1; ind += 1) {
35
+ const seg = segs[ind];
36
+ targets = targets.reduce((ret, target) => {
37
+ if (!isPlainObject(target)) return ret;
38
+ const targetObject = target;
39
+ const next = targetObject[seg];
40
+ if (isArray(next)) {
41
+ for (const item of next) {
42
+ ret.push(item);
43
+ }
44
+ } else if (next !== null && next !== void 0) ret.push(next);
45
+ return ret;
46
+ }, []);
47
+ }
48
+ const leaf = segs[segs.length - 1];
49
+ const pairs = [];
50
+ forEach(targets, (target) => {
51
+ if (!isPlainObject(target)) return;
52
+ pairs.push({ parent: target, leaf });
53
+ });
54
+ return pairs;
55
+ }
21
56
  var copyAndDepopulate = (docObject, operations, options = { mutable: true, idField: "_id" }) => {
22
57
  const mutable = options.mutable !== false;
23
58
  const idField = options.idField ?? "_id";
@@ -81,6 +116,130 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
81
116
  });
82
117
  return obj;
83
118
  };
119
+ var copyPaths = (docObject, operations, options = { mutable: true }) => {
120
+ const mutable = options.mutable !== false;
121
+ const obj = mutable ? docObject : cloneDeep(docObject);
122
+ forEach(Array.isArray(operations) ? operations : [], (op) => {
123
+ if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
124
+ const src = op.src;
125
+ const dest = op.dest;
126
+ if (src.length === 0 || dest.length === 0) return;
127
+ assertSafePath(src, "copyPaths");
128
+ assertSafePath(dest, "copyPaths");
129
+ if (src === dest) return;
130
+ forEach(resolveLeafParents(obj, src), ({ parent, leaf }) => {
131
+ if (!hasOwn(parent, leaf)) return;
132
+ set(parent, dest, cloneDeep(parent[leaf]));
133
+ });
134
+ });
135
+ return obj;
136
+ };
137
+ var movePaths = (docObject, operations, options = { mutable: true }) => {
138
+ const mutable = options.mutable !== false;
139
+ const obj = mutable ? docObject : cloneDeep(docObject);
140
+ forEach(Array.isArray(operations) ? operations : [], (op) => {
141
+ if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
142
+ const src = op.src;
143
+ const dest = op.dest;
144
+ if (src.length === 0 || dest.length === 0) return;
145
+ assertSafePath(src, "movePaths");
146
+ assertSafePath(dest, "movePaths");
147
+ if (src === dest) return;
148
+ forEach(resolveLeafParents(obj, src), ({ parent, leaf }) => {
149
+ if (!hasOwn(parent, leaf)) return;
150
+ const value = cloneDeep(parent[leaf]);
151
+ set(parent, dest, value);
152
+ if (dest === leaf || dest.startsWith(`${leaf}.`)) return;
153
+ delete parent[leaf];
154
+ });
155
+ });
156
+ return obj;
157
+ };
158
+ var sliceArrays = (docObject, operations, options = { mutable: true, maxSlice: DEFAULT_MAX_SLICE }) => {
159
+ const mutable = options.mutable !== false;
160
+ const maxSlice = options.maxSlice ?? DEFAULT_MAX_SLICE;
161
+ assertNonNegativeSafeInteger(maxSlice, "maxSlice", "sliceArrays");
162
+ const obj = mutable ? docObject : cloneDeep(docObject);
163
+ forEach(Array.isArray(operations) ? operations : [], (op) => {
164
+ if (!op || typeof op.src !== "string") return;
165
+ const src = op.src;
166
+ if (src.length === 0) return;
167
+ assertSafePath(src, "sliceArrays");
168
+ const rawDest = typeof op.dest === "undefined" ? void 0 : op.dest;
169
+ if (typeof rawDest !== "undefined") {
170
+ if (typeof rawDest !== "string" || rawDest.length === 0) return;
171
+ assertSafePath(rawDest, "sliceArrays");
172
+ }
173
+ const skip = op.skip ?? 0;
174
+ assertNonNegativeSafeInteger(skip, "skip", "sliceArrays");
175
+ let limit;
176
+ if (typeof op.limit !== "undefined") {
177
+ assertNonNegativeSafeInteger(op.limit, "limit", "sliceArrays");
178
+ limit = Math.min(op.limit, maxSlice);
179
+ }
180
+ forEach(resolveLeafParents(obj, src), ({ parent, leaf }) => {
181
+ const leafValue = parent[leaf];
182
+ if (!isArray(leafValue)) return;
183
+ const end = typeof limit === "undefined" ? void 0 : skip + limit;
184
+ const window = leafValue.slice(skip, end);
185
+ if (typeof rawDest === "undefined") {
186
+ set(parent, leaf, window);
187
+ } else {
188
+ set(parent, rawDest, window);
189
+ }
190
+ });
191
+ });
192
+ return obj;
193
+ };
194
+ var countPaths = (docObject, operations, options = { mutable: true }) => {
195
+ const mutable = options.mutable !== false;
196
+ const obj = mutable ? docObject : cloneDeep(docObject);
197
+ forEach(Array.isArray(operations) ? operations : [], (op) => {
198
+ if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
199
+ const src = op.src;
200
+ const dest = op.dest;
201
+ if (src.length === 0 || dest.length === 0) return;
202
+ assertSafePath(src, "countPaths");
203
+ assertSafePath(dest, "countPaths");
204
+ forEach(resolveLeafParents(obj, src), ({ parent, leaf }) => {
205
+ if (!hasOwn(parent, leaf)) return;
206
+ const leafValue = parent[leaf];
207
+ let count;
208
+ if (isArray(leafValue)) {
209
+ count = leafValue.length;
210
+ } else if (isPlainObject(leafValue)) {
211
+ count = Object.keys(leafValue).length;
212
+ } else if (leafValue === null || typeof leafValue === "undefined") {
213
+ count = 0;
214
+ } else {
215
+ count = 1;
216
+ }
217
+ set(parent, dest, count);
218
+ });
219
+ });
220
+ return obj;
221
+ };
222
+ var maskPaths = (docObject, operations, options = { mutable: true }) => {
223
+ const mutable = options.mutable !== false;
224
+ const obj = mutable ? docObject : cloneDeep(docObject);
225
+ forEach(Array.isArray(operations) ? operations : [], (op) => {
226
+ if (!op || typeof op.src !== "string") return;
227
+ const src = op.src;
228
+ if (src.length === 0) return;
229
+ assertSafePath(src, "maskPaths");
230
+ const replacement = Object.prototype.hasOwnProperty.call(op, "replacement") ? op.replacement : DEFAULT_MASK_REPLACEMENT;
231
+ forEach(resolveLeafParents(obj, src), ({ parent, leaf }) => {
232
+ if (!hasOwn(parent, leaf)) return;
233
+ set(parent, leaf, replacement);
234
+ });
235
+ });
236
+ return obj;
237
+ };
84
238
  export {
85
- copyAndDepopulate
239
+ copyAndDepopulate,
240
+ copyPaths,
241
+ countPaths,
242
+ maskPaths,
243
+ movePaths,
244
+ sliceArrays
86
245
  };