assign-gingerly 0.0.78 → 0.0.80

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/DX/paths.js CHANGED
@@ -27,6 +27,9 @@
27
27
  * The sp tag function uses this to auto-extract path strings from proxies.
28
28
  */
29
29
  const PATH_SYMBOL = Symbol('assign-gingerly-path');
30
+ function isPathProxy(value) {
31
+ return !!value && (typeof value === 'object' || typeof value === 'function') && PATH_SYMBOL in value;
32
+ }
30
33
  /**
31
34
  * Create a proxy for id-ref paths (#[varName]).
32
35
  * After the initial #[varName], further property access chains with ?. from the resolved element.
@@ -34,6 +37,7 @@ const PATH_SYMBOL = Symbol('assign-gingerly-path');
34
37
  */
35
38
  function createIdRefProxy(idRef, options) {
36
39
  function handler() { }
40
+ Object.defineProperty(handler, PATH_SYMBOL, { value: idRef });
37
41
  return new Proxy(handler, {
38
42
  get(_, prop) {
39
43
  if (prop === 'path' || prop === PATH_SYMBOL) {
@@ -53,7 +57,7 @@ function createIdRefProxy(idRef, options) {
53
57
  argStr = 'true';
54
58
  else if (arg === false)
55
59
  argStr = 'false';
56
- else if (arg && typeof arg === 'object' && PATH_SYMBOL in arg) {
60
+ else if (isPathProxy(arg)) {
57
61
  const fullPath = arg[PATH_SYMBOL];
58
62
  argStr = fullPath.startsWith('?.') ? fullPath.substring(2) : fullPath;
59
63
  }
@@ -77,6 +81,7 @@ function createPathProxy(prefix, options) {
77
81
  const aliasMap = options?.aka;
78
82
  // Use a function as the target to enable the apply trap
79
83
  function handler() { }
84
+ Object.defineProperty(handler, PATH_SYMBOL, { value: prefix.length > 0 ? `?.${prefix}` : '?.' });
80
85
  return new Proxy(handler, {
81
86
  get(_, prop) {
82
87
  if (prop === 'path' || prop === PATH_SYMBOL) {
@@ -114,7 +119,7 @@ function createPathProxy(prefix, options) {
114
119
  argStr = 'true';
115
120
  else if (arg === false)
116
121
  argStr = 'false';
117
- else if (arg && typeof arg === 'object' && PATH_SYMBOL in arg) {
122
+ else if (isPathProxy(arg)) {
118
123
  // Proxy arg — extract path without '?.' prefix
119
124
  const fullPath = arg[PATH_SYMBOL];
120
125
  argStr = fullPath.startsWith('?.') ? fullPath.substring(2) : fullPath;
@@ -167,12 +172,12 @@ export function paths(options) {
167
172
  * }
168
173
  */
169
174
  export function set(lhs) {
170
- const lhsStr = lhs && typeof lhs === 'object' && PATH_SYMBOL in lhs
175
+ const lhsStr = isPathProxy(lhs)
171
176
  ? lhs[PATH_SYMBOL]
172
177
  : String(lhs);
173
178
  return {
174
179
  to(rhs) {
175
- const rhsStr = rhs && typeof rhs === 'object' && PATH_SYMBOL in rhs
180
+ const rhsStr = isPathProxy(rhs)
176
181
  ? rhs[PATH_SYMBOL]
177
182
  : rhs;
178
183
  return { [lhsStr]: rhsStr };
@@ -198,7 +203,7 @@ export function set(lhs) {
198
203
  * // { assign: { incrementButton: '?.clone?.q?..increment', ... } }
199
204
  */
200
205
  export function smoothOver(value) {
201
- if (value && typeof value === 'object' && PATH_SYMBOL in value) {
206
+ if (isPathProxy(value)) {
202
207
  return value[PATH_SYMBOL];
203
208
  }
204
209
  if (Array.isArray(value)) {
@@ -294,13 +299,13 @@ export function sp(strings, ...values) {
294
299
  result.push(strings[i]);
295
300
  if (i < values.length) {
296
301
  const v = values[i];
297
- if (v && typeof v === 'object' && PATH_SYMBOL in v) {
302
+ if (isPathProxy(v)) {
298
303
  // Auto-extract path from proxy object
299
304
  result.push(v[PATH_SYMBOL]);
300
305
  }
301
306
  else if (Array.isArray(v)) {
302
307
  // Nested array — recursively extract paths from proxy elements
303
- result.push(v.map(el => el && typeof el === 'object' && PATH_SYMBOL in el ? el[PATH_SYMBOL] : el));
308
+ result.push(v.map(el => isPathProxy(el) ? el[PATH_SYMBOL] : el));
304
309
  }
305
310
  else {
306
311
  result.push(v);
@@ -349,7 +354,7 @@ export function md(strings, ...values) {
349
354
  result.push(strings[i]);
350
355
  if (i < values.length) {
351
356
  const v = values[i];
352
- if (v && typeof v === 'object' && PATH_SYMBOL in v) {
357
+ if (isPathProxy(v)) {
353
358
  // Proxy object → {prop, val}
354
359
  const pathStr = v[PATH_SYMBOL];
355
360
  result.push({ prop: extractPropName(pathStr), val: pathStr });
@@ -357,7 +362,7 @@ export function md(strings, ...values) {
357
362
  else if (Array.isArray(v)) {
358
363
  // Nested array — recursively convert proxy elements to {prop, val}
359
364
  result.push(v.map(el => {
360
- if (el && typeof el === 'object' && PATH_SYMBOL in el) {
365
+ if (isPathProxy(el)) {
361
366
  const pathStr = el[PATH_SYMBOL];
362
367
  return { prop: extractPropName(pathStr), val: pathStr };
363
368
  }
@@ -367,7 +372,7 @@ export function md(strings, ...values) {
367
372
  else if (v && typeof v === 'object' && 'prop' in v) {
368
373
  // Developer override object — extract val from proxy if present
369
374
  const processed = { ...v };
370
- if (processed.val && typeof processed.val === 'object' && PATH_SYMBOL in processed.val) {
375
+ if (isPathProxy(processed.val)) {
371
376
  processed.val = processed.val[PATH_SYMBOL];
372
377
  }
373
378
  result.push(processed);
package/DX/paths.ts CHANGED
@@ -27,7 +27,11 @@
27
27
  * Symbol used internally to detect path proxy objects.
28
28
  * The sp tag function uses this to auto-extract path strings from proxies.
29
29
  */
30
- const PATH_SYMBOL = Symbol('assign-gingerly-path');
30
+ const PATH_SYMBOL = Symbol('assign-gingerly-path');
31
+
32
+ function isPathProxy(value: unknown): value is { [PATH_SYMBOL]: string } {
33
+ return !!value && (typeof value === 'object' || typeof value === 'function') && PATH_SYMBOL in value;
34
+ }
31
35
 
32
36
  /**
33
37
  * Type that maps an object type to a proxy where every property access
@@ -58,13 +62,14 @@ export interface PathsOptions {
58
62
  * After the initial #[varName], further property access chains with ?. from the resolved element.
59
63
  * .path returns the #[varName] prefix (optionally with further ?. path).
60
64
  */
61
- function createIdRefProxy(idRef: string, options?: PathsOptions): any {
62
- function handler() {}
63
- return new Proxy(handler, {
64
- get(_, prop: string | symbol) {
65
- if (prop === 'path' || prop === PATH_SYMBOL) {
66
- return idRef;
67
- }
65
+ function createIdRefProxy(idRef: string, options?: PathsOptions): any {
66
+ function handler() {}
67
+ Object.defineProperty(handler, PATH_SYMBOL, { value: idRef });
68
+ return new Proxy(handler, {
69
+ get(_, prop: string | symbol) {
70
+ if (prop === 'path' || prop === PATH_SYMBOL) {
71
+ return idRef;
72
+ }
68
73
  if (typeof prop === 'symbol') return undefined;
69
74
 
70
75
  // Chain further path segments after the id ref
@@ -73,15 +78,15 @@ function createIdRefProxy(idRef: string, options?: PathsOptions): any {
73
78
  },
74
79
  apply(_, __, args) {
75
80
  if (args.length > 0) {
76
- const arg = args[0];
77
- let argStr: string;
78
- if (arg === true) argStr = 'true';
79
- else if (arg === false) argStr = 'false';
80
- else if (arg && typeof arg === 'object' && PATH_SYMBOL in arg) {
81
- const fullPath = arg[PATH_SYMBOL] as string;
82
- argStr = fullPath.startsWith('?.') ? fullPath.substring(2) : fullPath;
83
- }
84
- else argStr = String(arg);
81
+ const arg = args[0];
82
+ let argStr: string;
83
+ if (arg === true) argStr = 'true';
84
+ else if (arg === false) argStr = 'false';
85
+ else if (isPathProxy(arg)) {
86
+ const fullPath = arg[PATH_SYMBOL] as string;
87
+ argStr = fullPath.startsWith('?.') ? fullPath.substring(2) : fullPath;
88
+ }
89
+ else argStr = String(arg);
85
90
 
86
91
  const chained = `${idRef}?.${argStr}`;
87
92
  return createIdRefProxy(chained, options);
@@ -98,16 +103,17 @@ function createIdRefProxy(idRef: string, options?: PathsOptions): any {
98
103
  * When `aka` is provided, property names that match an alias *value* are output
99
104
  * using the alias *key* instead (reverse alias).
100
105
  */
101
- function createPathProxy(prefix: string, options?: PathsOptions): any {
102
- const aliasMap = options?.aka;
103
-
104
- // Use a function as the target to enable the apply trap
105
- function handler() {}
106
-
107
- return new Proxy(handler, {
108
- get(_, prop: string | symbol) {
109
- if (prop === 'path' || prop === PATH_SYMBOL) {
110
- return prefix.length > 0 ? `?.${prefix}` : '?.';
106
+ function createPathProxy(prefix: string, options?: PathsOptions): any {
107
+ const aliasMap = options?.aka;
108
+
109
+ // Use a function as the target to enable the apply trap
110
+ function handler() {}
111
+ Object.defineProperty(handler, PATH_SYMBOL, { value: prefix.length > 0 ? `?.${prefix}` : '?.' });
112
+
113
+ return new Proxy(handler, {
114
+ get(_, prop: string | symbol) {
115
+ if (prop === 'path' || prop === PATH_SYMBOL) {
116
+ return prefix.length > 0 ? `?.${prefix}` : '?.';
111
117
  }
112
118
  // Ignore symbol access (Symbol.iterator, Symbol.toPrimitive, etc.)
113
119
  if (typeof prop === 'symbol') return undefined;
@@ -135,16 +141,16 @@ function createPathProxy(prefix: string, options?: PathsOptions): any {
135
141
  apply(_, __, args) {
136
142
  // Method call syntax: $.querySelector('.username') → extends path with the argument
137
143
  if (args.length > 0) {
138
- const arg = args[0];
139
- let argStr: string;
140
- if (arg === true) argStr = 'true';
141
- else if (arg === false) argStr = 'false';
142
- else if (arg && typeof arg === 'object' && PATH_SYMBOL in arg) {
143
- // Proxy arg — extract path without '?.' prefix
144
- const fullPath = arg[PATH_SYMBOL] as string;
145
- argStr = fullPath.startsWith('?.') ? fullPath.substring(2) : fullPath;
146
- }
147
- else argStr = String(arg);
144
+ const arg = args[0];
145
+ let argStr: string;
146
+ if (arg === true) argStr = 'true';
147
+ else if (arg === false) argStr = 'false';
148
+ else if (isPathProxy(arg)) {
149
+ // Proxy arg — extract path without '?.' prefix
150
+ const fullPath = arg[PATH_SYMBOL] as string;
151
+ argStr = fullPath.startsWith('?.') ? fullPath.substring(2) : fullPath;
152
+ }
153
+ else argStr = String(arg);
148
154
 
149
155
  const newPath = prefix ? `${prefix}?.${argStr}` : argStr;
150
156
  return createPathProxy(newPath, options);
@@ -193,18 +199,18 @@ export function paths<T>(options?: PathsOptions): PathProxy<T> {
193
199
  * count: 1
194
200
  * }
195
201
  */
196
- export function set(lhs: any): { to: (rhs: any) => Record<string, any> } {
197
- const lhsStr = lhs && typeof lhs === 'object' && PATH_SYMBOL in lhs
198
- ? lhs[PATH_SYMBOL]
199
- : String(lhs);
200
- return {
201
- to(rhs: any): Record<string, any> {
202
- const rhsStr = rhs && typeof rhs === 'object' && PATH_SYMBOL in rhs
203
- ? rhs[PATH_SYMBOL]
204
- : rhs;
205
- return { [lhsStr]: rhsStr };
206
- }
207
- };
202
+ export function set(lhs: any): { to: (rhs: any) => Record<string, any> } {
203
+ const lhsStr = isPathProxy(lhs)
204
+ ? lhs[PATH_SYMBOL]
205
+ : String(lhs);
206
+ return {
207
+ to(rhs: any): Record<string, any> {
208
+ const rhsStr = isPathProxy(rhs)
209
+ ? rhs[PATH_SYMBOL]
210
+ : rhs;
211
+ return { [lhsStr]: rhsStr };
212
+ }
213
+ };
208
214
  }
209
215
 
210
216
  /**
@@ -225,19 +231,19 @@ export function set(lhs: any): { to: (rhs: any) => Record<string, any> } {
225
231
  * });
226
232
  * // { assign: { incrementButton: '?.clone?.q?..increment', ... } }
227
233
  */
228
- export function smoothOver(value: any): any {
229
- if (value && typeof value === 'object' && PATH_SYMBOL in value) {
230
- return value[PATH_SYMBOL];
231
- }
234
+ export function smoothOver(value: any): any {
235
+ if (isPathProxy(value)) {
236
+ return value[PATH_SYMBOL];
237
+ }
232
238
  if (Array.isArray(value)) {
233
239
  return value.map(smoothOver);
234
240
  }
235
241
  if (value && typeof value === 'object') {
236
242
  const proto = Object.getPrototypeOf(value);
237
243
  if (proto === Object.prototype || proto === null) {
238
- const result: Record<string, any> = {};
239
- for (const [k, v] of Object.entries(value)) {
240
- result[k] = smoothOver(v);
244
+ const result: Record<string, any> = {};
245
+ for (const [k, v] of Object.entries(value)) {
246
+ result[k] = smoothOver(v);
241
247
  }
242
248
  return result;
243
249
  }
@@ -322,23 +328,23 @@ export function forEachKeyIn<T>(
322
328
  * sp`${$.lastName}${[', ', $.middleName]}, ${$.firstName}`
323
329
  * // ['?.lastName', [', ', '?.middleName'], ', ', '?.firstName']
324
330
  */
325
- export function sp(strings: TemplateStringsArray, ...values: any[]): any[] {
331
+ export function sp(strings: TemplateStringsArray, ...values: any[]): any[] {
326
332
  const result: any[] = [];
327
333
  for (let i = 0; i < strings.length; i++) {
328
334
  if (strings[i]) result.push(strings[i]);
329
335
  if (i < values.length) {
330
- const v = values[i];
331
- if (v && typeof v === 'object' && PATH_SYMBOL in v) {
332
- // Auto-extract path from proxy object
333
- result.push(v[PATH_SYMBOL]);
334
- } else if (Array.isArray(v)) {
335
- // Nested array — recursively extract paths from proxy elements
336
- result.push(v.map(el =>
337
- el && typeof el === 'object' && PATH_SYMBOL in el ? el[PATH_SYMBOL] : el
338
- ));
339
- } else {
340
- result.push(v);
341
- }
336
+ const v = values[i];
337
+ if (isPathProxy(v)) {
338
+ // Auto-extract path from proxy object
339
+ result.push(v[PATH_SYMBOL]);
340
+ } else if (Array.isArray(v)) {
341
+ // Nested array — recursively extract paths from proxy elements
342
+ result.push(v.map(el =>
343
+ isPathProxy(el) ? el[PATH_SYMBOL] : el
344
+ ));
345
+ } else {
346
+ result.push(v);
347
+ }
342
348
  }
343
349
  }
344
350
  return result;
@@ -383,27 +389,27 @@ export function md(strings: TemplateStringsArray, ...values: any[]): any[] {
383
389
  for (let i = 0; i < strings.length; i++) {
384
390
  if (strings[i]) result.push(strings[i]);
385
391
  if (i < values.length) {
386
- const v = values[i];
387
- if (v && typeof v === 'object' && PATH_SYMBOL in v) {
388
- // Proxy object → {prop, val}
389
- const pathStr = v[PATH_SYMBOL] as string;
390
- result.push({ prop: extractPropName(pathStr), val: pathStr });
391
- } else if (Array.isArray(v)) {
392
- // Nested array — recursively convert proxy elements to {prop, val}
393
- result.push(v.map(el => {
394
- if (el && typeof el === 'object' && PATH_SYMBOL in el) {
395
- const pathStr = el[PATH_SYMBOL] as string;
396
- return { prop: extractPropName(pathStr), val: pathStr };
397
- }
398
- return el;
399
- }));
400
- } else if (v && typeof v === 'object' && 'prop' in v) {
401
- // Developer override object — extract val from proxy if present
402
- const processed = { ...v };
403
- if (processed.val && typeof processed.val === 'object' && PATH_SYMBOL in processed.val) {
404
- processed.val = processed.val[PATH_SYMBOL];
405
- }
406
- result.push(processed);
392
+ const v = values[i];
393
+ if (isPathProxy(v)) {
394
+ // Proxy object → {prop, val}
395
+ const pathStr = v[PATH_SYMBOL] as string;
396
+ result.push({ prop: extractPropName(pathStr), val: pathStr });
397
+ } else if (Array.isArray(v)) {
398
+ // Nested array — recursively convert proxy elements to {prop, val}
399
+ result.push(v.map(el => {
400
+ if (isPathProxy(el)) {
401
+ const pathStr = el[PATH_SYMBOL] as string;
402
+ return { prop: extractPropName(pathStr), val: pathStr };
403
+ }
404
+ return el;
405
+ }));
406
+ } else if (v && typeof v === 'object' && 'prop' in v) {
407
+ // Developer override object — extract val from proxy if present
408
+ const processed = { ...v };
409
+ if (isPathProxy(processed.val)) {
410
+ processed.val = processed.val[PATH_SYMBOL];
411
+ }
412
+ result.push(processed);
407
413
  } else {
408
414
  result.push(v);
409
415
  }