assign-gingerly 0.0.10 → 0.0.12

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/README.md CHANGED
@@ -607,7 +607,7 @@ When you access `element.enh.set.enhKey.property`, the proxy:
607
607
 
608
608
  1. **Checks the registry**: Looks for a registry item with `enhKey` matching the property name
609
609
  2. **Spawns if needed**: If found and the enhancement doesn't exist or is the wrong type:
610
- - Creates a `SpawnContext` with `{ mountInfo: registryItem }`
610
+ - Creates a `SpawnContext` with `{ config: registryItem }`
611
611
  - Calls the constructor with `(element, ctx, initVals)`
612
612
  - If a non-matching object already exists at `element.enh[enhKey]`, it's passed as `initVals`
613
613
  - Stores the spawned instance at `element.enh[enhKey]`
@@ -628,23 +628,51 @@ This approach is part of a proposal to WHATWG for standardizing element enhancem
628
628
  Enhancement classes should follow this constructor signature:
629
629
 
630
630
  ```TypeScript
631
- interface SpawnContext<T> {
632
- mountInfo: IBaseRegistryItem<T>;
631
+ interface SpawnContext<T, TMountContext = any> {
632
+ config: IBaseRegistryItem<T>;
633
+ mountCtx?: TMountContext; // Optional custom context passed by caller
633
634
  }
634
635
 
635
636
  class Enhancement {
636
637
  constructor(
637
638
  oElement?: Element, // The element being enhanced
638
- ctx?: SpawnContext, // Context with registry item info
639
+ ctx?: SpawnContext, // Context with registry item info and optional mountCtx
639
640
  initVals?: Partial<T> // Initial values if property existed
640
641
  ) {
641
642
  // Your initialization logic
643
+ // Access custom context via ctx.mountCtx if provided
642
644
  }
643
645
  }
644
646
  ```
645
647
 
646
648
  All parameters are optional for backward compatibility with existing code.
647
649
 
650
+ **Passing Custom Context:**
651
+
652
+ You can pass custom context when calling `enh.get()` or `enh.whenResolved()`:
653
+
654
+ ```TypeScript
655
+ // Pass custom context to the spawned instance
656
+ const myContext = { userId: 123, permissions: ['read', 'write'] };
657
+ const instance = element.enh.get(registryItem, myContext);
658
+
659
+ // The constructor receives it via ctx.mountCtx
660
+ class MyEnhancement {
661
+ constructor(oElement, ctx, initVals) {
662
+ console.log(ctx.mountCtx.userId); // 123
663
+ console.log(ctx.mountCtx.permissions); // ['read', 'write']
664
+ }
665
+ }
666
+ ```
667
+
668
+ This is useful for:
669
+ - Passing authentication/authorization context
670
+ - Providing configuration that varies per invocation
671
+ - Sharing state between caller and enhancement
672
+ - Dependency injection of services or utilities
673
+
674
+ **Note**: The `mountCtx` is only available when explicitly calling `enh.get()` or `enh.whenResolved()`. It's not available when accessing via the `enh.set` proxy (since that's a property getter with no way to pass parameters).
675
+
648
676
  ### Registry Item with enhKey
649
677
 
650
678
  Registry items now support optional `enhKey`, `withAttrs`, `canSpawn`, and `lifecycleKeys` properties:
@@ -1031,6 +1059,11 @@ const customRegistryItem = {
1031
1059
  // Wait for the enhancement to be fully initialized
1032
1060
  const instance = await element.enh.whenResolved(registryItem);
1033
1061
  console.log(instance.data); // Data is loaded and ready
1062
+
1063
+ // With custom context
1064
+ const authContext = { token: 'abc123', userId: 456 };
1065
+ const instanceWithContext = await element.enh.whenResolved(registryItem, authContext);
1066
+ // The constructor receives authContext via ctx.mountCtx
1034
1067
  ```
1035
1068
 
1036
1069
  **How `enh.whenResolved()` works:**
@@ -1185,7 +1218,7 @@ static canSpawn(obj: any, ctx?: SpawnContext<T>): boolean
1185
1218
  ```
1186
1219
 
1187
1220
  - `obj`: The target object being enhanced (element, plain object, etc.)
1188
- - `ctx`: Optional spawn context containing `{ mountInfo: IBaseRegistryItem<T> }`
1221
+ - `ctx`: Optional spawn context containing `{ config: IBaseRegistryItem<T> }`
1189
1222
  - Returns: `true` to allow spawning, `false` to block
1190
1223
 
1191
1224
  ### Use Cases
package/assignGingerly.js CHANGED
@@ -315,7 +315,7 @@ export function assignGingerly(target, source, options) {
315
315
  const SpawnClass = registryItem.spawn;
316
316
  // Check canSpawn if it exists
317
317
  if (typeof SpawnClass.canSpawn === 'function') {
318
- const ctx = { mountInfo: registryItem };
318
+ const ctx = { config: registryItem };
319
319
  if (!SpawnClass.canSpawn(target, ctx)) {
320
320
  // canSpawn returned false, skip spawning
321
321
  continue;
@@ -323,7 +323,7 @@ export function assignGingerly(target, source, options) {
323
323
  }
324
324
  // If target is an Element and registryItem has enhKey, pass element to constructor
325
325
  if (registryItem.enhKey && typeof Element !== 'undefined' && target instanceof Element) {
326
- const ctx = { mountInfo: registryItem };
326
+ const ctx = { config: registryItem };
327
327
  const initVals = target.enh?.[registryItem.enhKey] &&
328
328
  !(target.enh[registryItem.enhKey] instanceof SpawnClass)
329
329
  ? target.enh[registryItem.enhKey]
@@ -344,9 +344,11 @@ export function assignGingerly(target, source, options) {
344
344
  }
345
345
  }
346
346
  // Find the mapped property name
347
- const mappedKey = registryItem.symlinks[sym];
348
- if (mappedKey && instance && typeof instance === 'object') {
349
- instance[mappedKey] = value;
347
+ if (registryItem.symlinks) {
348
+ const mappedKey = registryItem.symlinks[sym];
349
+ if (mappedKey && instance && typeof instance === 'object') {
350
+ instance[mappedKey] = value;
351
+ }
350
352
  }
351
353
  }
352
354
  }
@@ -370,7 +372,7 @@ export function assignGingerly(target, source, options) {
370
372
  const SpawnClass = registryItem.spawn;
371
373
  // Check canSpawn if it exists
372
374
  if (typeof SpawnClass.canSpawn === 'function') {
373
- const ctx = { mountInfo: registryItem };
375
+ const ctx = { config: registryItem };
374
376
  if (!SpawnClass.canSpawn(target, ctx)) {
375
377
  // canSpawn returned false, skip spawning
376
378
  return true;
@@ -378,7 +380,7 @@ export function assignGingerly(target, source, options) {
378
380
  }
379
381
  // If target is an Element and registryItem has enhKey, pass element to constructor
380
382
  if (registryItem.enhKey && typeof Element !== 'undefined' && target instanceof Element) {
381
- const ctx = { mountInfo: registryItem };
383
+ const ctx = { config: registryItem };
382
384
  const initVals = target.enh?.[registryItem.enhKey] &&
383
385
  !(target.enh[registryItem.enhKey] instanceof SpawnClass)
384
386
  ? target.enh[registryItem.enhKey]
@@ -397,9 +399,11 @@ export function assignGingerly(target, source, options) {
397
399
  target.enh[registryItem.enhKey] = instance;
398
400
  }
399
401
  }
400
- const mappedKey = registryItem.symlinks[prop];
401
- if (mappedKey && instance && typeof instance === 'object') {
402
- instance[mappedKey] = value;
402
+ if (registryItem.symlinks) {
403
+ const mappedKey = registryItem.symlinks[prop];
404
+ if (mappedKey && instance && typeof instance === 'object') {
405
+ instance[mappedKey] = value;
406
+ }
403
407
  }
404
408
  }
405
409
  }
package/assignGingerly.ts CHANGED
@@ -1,22 +1,6 @@
1
- /**
2
- * Configuration for enhancing elements with class instances
3
- */
4
- export interface EnhancementConfig<T = any> {
5
- spawn: {
6
- new (oElement?: Element, ctx?: SpawnContext<T>, initVals?: Partial<T>): T;
7
- canSpawn?: (obj: any, ctx?: SpawnContext<T>) => boolean;
8
- };
9
- symlinks: { [key: string | symbol]: keyof T };
10
- enhKey?: string;
11
- lifecycleKeys?: {
12
- dispose?: string;
13
- resolved?: string;
14
- };
15
- }
16
1
 
17
- export interface SpawnContext<T = any> {
18
- mountInfo: EnhancementConfig<T>;
19
- }
2
+
3
+ import { EnhancementConfig } from "./types";
20
4
 
21
5
  /**
22
6
  * @deprecated Use EnhancementConfig instead
@@ -379,7 +363,7 @@ export function assignGingerly(
379
363
 
380
364
  // Check canSpawn if it exists
381
365
  if (typeof SpawnClass.canSpawn === 'function') {
382
- const ctx = { mountInfo: registryItem };
366
+ const ctx = { config: registryItem };
383
367
  if (!SpawnClass.canSpawn(target, ctx)) {
384
368
  // canSpawn returned false, skip spawning
385
369
  continue;
@@ -388,7 +372,7 @@ export function assignGingerly(
388
372
 
389
373
  // If target is an Element and registryItem has enhKey, pass element to constructor
390
374
  if (registryItem.enhKey && typeof Element !== 'undefined' && target instanceof Element) {
391
- const ctx = { mountInfo: registryItem };
375
+ const ctx = { config: registryItem };
392
376
  const initVals = (target as any).enh?.[registryItem.enhKey] &&
393
377
  !((target as any).enh[registryItem.enhKey] instanceof SpawnClass)
394
378
  ? (target as any).enh[registryItem.enhKey]
@@ -411,10 +395,13 @@ export function assignGingerly(
411
395
  }
412
396
 
413
397
  // Find the mapped property name
414
- const mappedKey = registryItem.symlinks[sym];
415
- if (mappedKey && instance && typeof instance === 'object') {
416
- (instance as any)[mappedKey] = value;
398
+ if(registryItem.symlinks){
399
+ const mappedKey = registryItem.symlinks[sym];
400
+ if (mappedKey && instance && typeof instance === 'object') {
401
+ (instance as any)[mappedKey] = value;
402
+ }
417
403
  }
404
+
418
405
  }
419
406
  }
420
407
  }
@@ -442,7 +429,7 @@ export function assignGingerly(
442
429
 
443
430
  // Check canSpawn if it exists
444
431
  if (typeof SpawnClass.canSpawn === 'function') {
445
- const ctx = { mountInfo: registryItem };
432
+ const ctx = { config: registryItem };
446
433
  if (!SpawnClass.canSpawn(target, ctx)) {
447
434
  // canSpawn returned false, skip spawning
448
435
  return true;
@@ -451,7 +438,7 @@ export function assignGingerly(
451
438
 
452
439
  // If target is an Element and registryItem has enhKey, pass element to constructor
453
440
  if (registryItem.enhKey && typeof Element !== 'undefined' && target instanceof Element) {
454
- const ctx = { mountInfo: registryItem };
441
+ const ctx = { config: registryItem };
455
442
  const initVals = (target as any).enh?.[registryItem.enhKey] &&
456
443
  !((target as any).enh[registryItem.enhKey] instanceof SpawnClass)
457
444
  ? (target as any).enh[registryItem.enhKey]
@@ -471,11 +458,13 @@ export function assignGingerly(
471
458
  (target as any).enh[registryItem.enhKey] = instance;
472
459
  }
473
460
  }
474
-
475
- const mappedKey = registryItem.symlinks[prop];
476
- if (mappedKey && instance && typeof instance === 'object') {
477
- (instance as any)[mappedKey] = value;
461
+ if(registryItem.symlinks){
462
+ const mappedKey = registryItem.symlinks[prop];
463
+ if (mappedKey && instance && typeof instance === 'object') {
464
+ (instance as any)[mappedKey] = value;
465
+ }
478
466
  }
467
+
479
468
  }
480
469
  }
481
470
  return true;
@@ -48,9 +48,10 @@ class ElementEnhancementContainer {
48
48
  /**
49
49
  * Get or spawn an instance for a registry item
50
50
  * @param registryItem - The registry item to get/spawn instance for
51
+ * @param mountCtx - Optional context to pass to the spawned instance
51
52
  * @returns The spawned instance
52
53
  */
53
- get(registryItem) {
54
+ get(registryItem, mountCtx) {
54
55
  const element = this.element;
55
56
  // Get the registry from customElementRegistry
56
57
  const registry = element.customElementRegistry?.enhancementRegistry;
@@ -75,7 +76,7 @@ class ElementEnhancementContainer {
75
76
  const SpawnClass = registryItem.spawn;
76
77
  // Check canSpawn if it exists
77
78
  if (typeof SpawnClass.canSpawn === 'function') {
78
- const ctx = { mountInfo: registryItem };
79
+ const ctx = { config: registryItem, mountCtx };
79
80
  if (!SpawnClass.canSpawn(element, ctx)) {
80
81
  // canSpawn returned false, return undefined
81
82
  return undefined;
@@ -83,7 +84,7 @@ class ElementEnhancementContainer {
83
84
  }
84
85
  // Check if there's an enhKey
85
86
  if (registryItem.enhKey) {
86
- const ctx = { mountInfo: registryItem };
87
+ const ctx = { config: registryItem, mountCtx };
87
88
  const self = this;
88
89
  // Parse attributes if withAttrs is defined
89
90
  let attrInitVals = undefined;
@@ -111,7 +112,7 @@ class ElementEnhancementContainer {
111
112
  }
112
113
  else {
113
114
  // No enhKey, just spawn with element
114
- const ctx = { mountInfo: registryItem };
115
+ const ctx = { config: registryItem, mountCtx };
115
116
  instance = new SpawnClass(element, ctx);
116
117
  }
117
118
  // Store in global instance map
@@ -152,16 +153,17 @@ class ElementEnhancementContainer {
152
153
  /**
153
154
  * Wait for an enhancement instance to be resolved
154
155
  * @param registryItem - The registry item to wait for
156
+ * @param mountCtx - Optional context to pass to the spawned instance
155
157
  * @returns Promise that resolves with the spawned instance
156
158
  */
157
- async whenResolved(registryItem) {
159
+ async whenResolved(registryItem, mountCtx) {
158
160
  const lifecycleKeys = normalizeLifecycleKeys(registryItem?.lifecycleKeys);
159
161
  const resolvedKey = lifecycleKeys?.resolved;
160
162
  if (resolvedKey === undefined) {
161
163
  throw new Error('Must specify resolved key in lifecycleKeys');
162
164
  }
163
- // Get or spawn the instance
164
- const spawnedInstance = this.get(registryItem);
165
+ // Get or spawn the instance (pass mountCtx through)
166
+ const spawnedInstance = this.get(registryItem, mountCtx);
165
167
  // Check if already resolved
166
168
  if (spawnedInstance[resolvedKey]) {
167
169
  return spawnedInstance;
@@ -209,7 +211,7 @@ class ElementEnhancementContainer {
209
211
  const SpawnClass = registryItem.spawn;
210
212
  // Check canSpawn if it exists
211
213
  if (typeof SpawnClass.canSpawn === 'function') {
212
- const ctx = { mountInfo: registryItem };
214
+ const ctx = { config: registryItem };
213
215
  if (!SpawnClass.canSpawn(element, ctx)) {
214
216
  // canSpawn returned false, return undefined
215
217
  return undefined;
@@ -221,7 +223,7 @@ class ElementEnhancementContainer {
221
223
  initVals = self[prop];
222
224
  }
223
225
  // Create spawn context
224
- const ctx = { mountInfo: registryItem };
226
+ const ctx = { config: registryItem };
225
227
  // Spawn the instance
226
228
  instance = new SpawnClass(element, ctx, initVals);
227
229
  // Store in global instance map
@@ -114,9 +114,10 @@ class ElementEnhancementContainer {
114
114
  /**
115
115
  * Get or spawn an instance for a registry item
116
116
  * @param registryItem - The registry item to get/spawn instance for
117
+ * @param mountCtx - Optional context to pass to the spawned instance
117
118
  * @returns The spawned instance
118
119
  */
119
- get(registryItem: any): any {
120
+ get(registryItem: any, mountCtx?: any): any {
120
121
  const element = this.element;
121
122
 
122
123
  // Get the registry from customElementRegistry
@@ -148,7 +149,7 @@ class ElementEnhancementContainer {
148
149
 
149
150
  // Check canSpawn if it exists
150
151
  if (typeof SpawnClass.canSpawn === 'function') {
151
- const ctx = { mountInfo: registryItem };
152
+ const ctx = { config: registryItem, mountCtx };
152
153
  if (!SpawnClass.canSpawn(element, ctx)) {
153
154
  // canSpawn returned false, return undefined
154
155
  return undefined;
@@ -157,7 +158,7 @@ class ElementEnhancementContainer {
157
158
 
158
159
  // Check if there's an enhKey
159
160
  if (registryItem.enhKey) {
160
- const ctx = { mountInfo: registryItem };
161
+ const ctx = { config: registryItem, mountCtx };
161
162
  const self = this as any;
162
163
 
163
164
  // Parse attributes if withAttrs is defined
@@ -192,7 +193,7 @@ class ElementEnhancementContainer {
192
193
  self[registryItem.enhKey] = instance;
193
194
  } else {
194
195
  // No enhKey, just spawn with element
195
- const ctx = { mountInfo: registryItem };
196
+ const ctx = { config: registryItem, mountCtx };
196
197
  instance = new SpawnClass(element, ctx);
197
198
  }
198
199
 
@@ -243,9 +244,10 @@ class ElementEnhancementContainer {
243
244
  /**
244
245
  * Wait for an enhancement instance to be resolved
245
246
  * @param registryItem - The registry item to wait for
247
+ * @param mountCtx - Optional context to pass to the spawned instance
246
248
  * @returns Promise that resolves with the spawned instance
247
249
  */
248
- async whenResolved(registryItem: any): Promise<any> {
250
+ async whenResolved(registryItem: any, mountCtx?: any): Promise<any> {
249
251
  const lifecycleKeys = normalizeLifecycleKeys(registryItem?.lifecycleKeys);
250
252
  const resolvedKey = lifecycleKeys?.resolved;
251
253
 
@@ -253,8 +255,8 @@ class ElementEnhancementContainer {
253
255
  throw new Error('Must specify resolved key in lifecycleKeys');
254
256
  }
255
257
 
256
- // Get or spawn the instance
257
- const spawnedInstance = this.get(registryItem);
258
+ // Get or spawn the instance (pass mountCtx through)
259
+ const spawnedInstance = this.get(registryItem, mountCtx);
258
260
 
259
261
  // Check if already resolved
260
262
  if ((spawnedInstance as any)[resolvedKey]) {
@@ -315,7 +317,7 @@ class ElementEnhancementContainer {
315
317
 
316
318
  // Check canSpawn if it exists
317
319
  if (typeof SpawnClass.canSpawn === 'function') {
318
- const ctx = { mountInfo: registryItem };
320
+ const ctx = { config: registryItem };
319
321
  if (!SpawnClass.canSpawn(element, ctx)) {
320
322
  // canSpawn returned false, return undefined
321
323
  return undefined;
@@ -330,7 +332,7 @@ class ElementEnhancementContainer {
330
332
  }
331
333
 
332
334
  // Create spawn context
333
- const ctx = { mountInfo: registryItem };
335
+ const ctx = { config: registryItem };
334
336
 
335
337
  // Spawn the instance
336
338
  instance = new SpawnClass(element, ctx, initVals);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assign-gingerly",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "This package provides a utility function for carefully merging one object into another.",
5
5
  "homepage": "https://github.com/bahrus/assign-gingerly#readme",
6
6
  "bugs": {
package/types.d.ts CHANGED
@@ -121,8 +121,9 @@ export type AttrPatterns<T = any> = {
121
121
  };
122
122
 
123
123
 
124
- export interface SpawnContext<T = any> {
125
- mountInfo: EnhancementConfig<T>;
124
+ export interface SpawnContext<T = any, TMountContext = any> {
125
+ config: EnhancementConfig<T>;
126
+ mountCtx?: TMountContext;
126
127
  }
127
128
 
128
129
  /**