assign-gingerly 0.0.76 โ†’ 0.0.78

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/emojis.ts CHANGED
@@ -22,7 +22,7 @@
22
22
  * | ๐Ÿท๏ธ | builtIns.microDataJoin |
23
23
  * | ๐Ÿ“‹ | builtIns.manageTemplateList |
24
24
  */
25
- export const builtInEmoji: Record<string, string> = {
25
+ export const builtInEmoji= {
26
26
  '๐Ÿ“ฆ': 'builtIns.lazyLoad',
27
27
  '๐ŸŽš๏ธ': 'builtIns.lazyLoadSwitch',
28
28
  '๐Ÿ”—': 'builtIns.join',
@@ -31,7 +31,7 @@ export const builtInEmoji: Record<string, string> = {
31
31
  '๐Ÿ“Š': 'builtIns.rangeSelector',
32
32
  };
33
33
 
34
- export const akaMethods: Record<string, string> = {
34
+ export const akaMethods = {
35
35
  '๐Ÿ”': 'querySelector',
36
36
  '๐Ÿงบ': 'querySelectorAll',
37
37
  '+': 'add',
@@ -53,7 +53,7 @@ export const akaMethods: Record<string, string> = {
53
53
  //'๐Ÿงฉ': 'includes'
54
54
  };
55
55
 
56
- export const aka: Record<string, string> = {
56
+ export const aka = {
57
57
  'ยฉ๏ธ': 'content?.cloneNode?.true',
58
58
  //'๐Ÿ”Ž': 'clone?.querySelector'
59
59
  // textContent is a property, not a method โ€” aliasing it via akaMethods
package/assignFeatures.js CHANGED
@@ -84,10 +84,8 @@ function isAsyncResolution(spawnish) {
84
84
  }
85
85
  /**
86
86
  * Resolves all configured spawns for the target constructor and caches them.
87
- * Returns a Promise if any resolution is async, otherwise undefined.
88
87
  */
89
- function resolveAndCacheSpawns(ctr, features, supportedFeatures) {
90
- let hasAsync = false;
88
+ async function resolveAndCacheSpawns(ctr, features, supportedFeatures) {
91
89
  const asyncResolutions = [];
92
90
  for (const key of Object.keys(features)) {
93
91
  const classCache = getOrCreateClassCache(ctr);
@@ -104,7 +102,6 @@ function resolveAndCacheSpawns(ctr, features, supportedFeatures) {
104
102
  continue;
105
103
  }
106
104
  if (isAsyncResolution(spawnish)) {
107
- hasAsync = true;
108
105
  asyncResolutions.push((async () => {
109
106
  const resolved = await resolveSpawn(spawnish);
110
107
  classCache.set(key, resolved);
@@ -114,10 +111,9 @@ function resolveAndCacheSpawns(ctr, features, supportedFeatures) {
114
111
  classCache.set(key, spawnish);
115
112
  }
116
113
  }
117
- if (hasAsync) {
118
- return Promise.all(asyncResolutions).then(() => undefined);
114
+ if (asyncResolutions.length > 0) {
115
+ await Promise.all(asyncResolutions);
119
116
  }
120
- return undefined;
121
117
  }
122
118
  /**
123
119
  * Installs a getter/setter pair on the constructor's prototype for the given feature key.
@@ -288,7 +284,7 @@ function installCallbackForwarding(ctr, key, callbacks) {
288
284
  featureKeys.add(key);
289
285
  }
290
286
  }
291
- function installOneFeature(ctr, key, features, supportedFeatures, featuresRegistry) {
287
+ async function installOneFeature(ctr, key, features, supportedFeatures, featuresRegistry) {
292
288
  // 1. Confirm the key is opted-in via supportedFeatures
293
289
  if (!(key in supportedFeatures)) {
294
290
  throw new Error(`assignFeatures: "${key}" is not declared in ${ctr.name || 'constructor'}.supportedFeatures`);
@@ -322,27 +318,13 @@ function installOneFeature(ctr, key, features, supportedFeatures, featuresRegist
322
318
  if (resolvedSpawn && !isAsyncSpawn(resolvedSpawn) &&
323
319
  Object.hasOwn(resolvedSpawn, 'onAssigned') &&
324
320
  typeof resolvedSpawn.onAssigned === 'function') {
325
- const result = resolvedSpawn.onAssigned(ctr, featureConfig, key);
326
- if (result && typeof result.then === 'function') {
327
- return result;
328
- }
321
+ await resolvedSpawn.onAssigned(ctr, featureConfig, key);
329
322
  }
330
- return undefined;
331
323
  }
332
- function installAllFeatures(ctr, features, supportedFeatures, featuresRegistry) {
333
- let asyncResult;
324
+ async function installAllFeatures(ctr, features, supportedFeatures, featuresRegistry) {
334
325
  for (const key of Object.keys(features)) {
335
- const result = installOneFeature(ctr, key, features, supportedFeatures, featuresRegistry);
336
- if (result) {
337
- if (!asyncResult) {
338
- asyncResult = result.then(() => undefined);
339
- }
340
- else {
341
- asyncResult = asyncResult.then(() => result.then(() => undefined));
342
- }
343
- }
326
+ await installOneFeature(ctr, key, features, supportedFeatures, featuresRegistry);
344
327
  }
345
- return asyncResult;
346
328
  }
347
329
  /**
348
330
  * Core assignFeatures implementation.
@@ -357,7 +339,7 @@ function installAllFeatures(ctr, features, supportedFeatures, featuresRegistry)
357
339
  * @param features - Map of feature keys to their injection configs
358
340
  * @param featuresRegistry - The registry to store injections in
359
341
  */
360
- export function assignFeatures(ctr, features, featuresRegistry) {
342
+ export async function assignFeatures(ctr, features, featuresRegistry) {
361
343
  // Validate that the constructor has static supportedFeatures
362
344
  const supportedFeatures = ctr.supportedFeatures;
363
345
  if (!supportedFeatures) {
@@ -366,11 +348,8 @@ export function assignFeatures(ctr, features, featuresRegistry) {
366
348
  // Resolve all configured spawns before installing getters. This is the single
367
349
  // source of truth for spawn resolution; other callers (defineWithFeatures, etc.)
368
350
  // delegate to assignFeatures.
369
- const spawnResolution = resolveAndCacheSpawns(ctr, features, supportedFeatures);
370
- if (spawnResolution) {
371
- return spawnResolution.then(() => installAllFeatures(ctr, features, supportedFeatures, featuresRegistry));
372
- }
373
- return installAllFeatures(ctr, features, supportedFeatures, featuresRegistry);
351
+ await resolveAndCacheSpawns(ctr, features, supportedFeatures);
352
+ await installAllFeatures(ctr, features, supportedFeatures, featuresRegistry);
374
353
  }
375
354
  /**
376
355
  * Captures own-properties that shadow feature getters and stores them as initVals.
package/assignFeatures.ts CHANGED
@@ -96,14 +96,12 @@ function isAsyncResolution(spawnish: any): boolean {
96
96
 
97
97
  /**
98
98
  * Resolves all configured spawns for the target constructor and caches them.
99
- * Returns a Promise if any resolution is async, otherwise undefined.
100
99
  */
101
- function resolveAndCacheSpawns(
100
+ async function resolveAndCacheSpawns(
102
101
  ctr: Function,
103
102
  features: FeatureConfigsMap,
104
103
  supportedFeatures: SupportedFeaturesMap
105
- ): Promise<void> | undefined {
106
- let hasAsync = false;
104
+ ): Promise<void> {
107
105
  const asyncResolutions: Promise<void>[] = [];
108
106
 
109
107
  for (const key of Object.keys(features)) {
@@ -123,7 +121,6 @@ function resolveAndCacheSpawns(
123
121
  }
124
122
 
125
123
  if (isAsyncResolution(spawnish)) {
126
- hasAsync = true;
127
124
  asyncResolutions.push((async () => {
128
125
  const resolved = await resolveSpawn(spawnish);
129
126
  classCache.set(key, resolved);
@@ -133,10 +130,9 @@ function resolveAndCacheSpawns(
133
130
  }
134
131
  }
135
132
 
136
- if (hasAsync) {
137
- return Promise.all(asyncResolutions).then(() => undefined);
133
+ if (asyncResolutions.length > 0) {
134
+ await Promise.all(asyncResolutions);
138
135
  }
139
- return undefined;
140
136
  }
141
137
 
142
138
  /**
@@ -349,13 +345,13 @@ function installCallbackForwarding(
349
345
  }
350
346
  }
351
347
 
352
- function installOneFeature(
348
+ async function installOneFeature(
353
349
  ctr: Function,
354
350
  key: string,
355
351
  features: FeatureConfigsMap,
356
352
  supportedFeatures: SupportedFeaturesMap,
357
353
  featuresRegistry: FeaturesRegistry
358
- ): Promise<void> | undefined {
354
+ ): Promise<void> {
359
355
  // 1. Confirm the key is opted-in via supportedFeatures
360
356
  if (!(key in supportedFeatures)) {
361
357
  throw new Error(
@@ -401,32 +397,19 @@ function installOneFeature(
401
397
  if (resolvedSpawn && !isAsyncSpawn(resolvedSpawn) &&
402
398
  Object.hasOwn(resolvedSpawn, 'onAssigned') &&
403
399
  typeof (resolvedSpawn as any).onAssigned === 'function') {
404
- const result = (resolvedSpawn as any).onAssigned(ctr, featureConfig, key);
405
- if (result && typeof result.then === 'function') {
406
- return result;
407
- }
400
+ await (resolvedSpawn as any).onAssigned(ctr, featureConfig, key);
408
401
  }
409
- return undefined;
410
402
  }
411
403
 
412
- function installAllFeatures(
404
+ async function installAllFeatures(
413
405
  ctr: Function,
414
406
  features: FeatureConfigsMap,
415
407
  supportedFeatures: SupportedFeaturesMap,
416
408
  featuresRegistry: FeaturesRegistry
417
- ): Promise<void> | undefined {
418
- let asyncResult: Promise<void> | undefined;
409
+ ): Promise<void> {
419
410
  for (const key of Object.keys(features)) {
420
- const result = installOneFeature(ctr, key, features, supportedFeatures, featuresRegistry);
421
- if (result) {
422
- if (!asyncResult) {
423
- asyncResult = result.then(() => undefined);
424
- } else {
425
- asyncResult = asyncResult.then(() => result.then(() => undefined));
426
- }
427
- }
411
+ await installOneFeature(ctr, key, features, supportedFeatures, featuresRegistry);
428
412
  }
429
- return asyncResult;
430
413
  }
431
414
 
432
415
  /**
@@ -442,11 +425,11 @@ function installAllFeatures(
442
425
  * @param features - Map of feature keys to their injection configs
443
426
  * @param featuresRegistry - The registry to store injections in
444
427
  */
445
- export function assignFeatures(
428
+ export async function assignFeatures(
446
429
  ctr: Function,
447
430
  features: FeatureConfigsMap,
448
431
  featuresRegistry: FeaturesRegistry
449
- ): Promise<void> | undefined {
432
+ ): Promise<void> {
450
433
  // Validate that the constructor has static supportedFeatures
451
434
  const supportedFeatures: SupportedFeaturesMap | undefined = (ctr as any).supportedFeatures;
452
435
 
@@ -459,15 +442,8 @@ export function assignFeatures(
459
442
  // Resolve all configured spawns before installing getters. This is the single
460
443
  // source of truth for spawn resolution; other callers (defineWithFeatures, etc.)
461
444
  // delegate to assignFeatures.
462
- const spawnResolution = resolveAndCacheSpawns(ctr, features, supportedFeatures);
463
-
464
- if (spawnResolution) {
465
- return spawnResolution.then(() =>
466
- installAllFeatures(ctr, features, supportedFeatures, featuresRegistry)
467
- );
468
- }
469
-
470
- return installAllFeatures(ctr, features, supportedFeatures, featuresRegistry);
445
+ await resolveAndCacheSpawns(ctr, features, supportedFeatures);
446
+ await installAllFeatures(ctr, features, supportedFeatures, featuresRegistry);
471
447
  }
472
448
 
473
449
  /**
@@ -682,7 +658,7 @@ export class PropertyBag {
682
658
  declare global {
683
659
  interface CustomElementRegistry {
684
660
  featuresRegistry: FeaturesRegistry;
685
- assignFeatures(ctr: Function, features: FeatureConfigsMap): Promise<void> | undefined;
661
+ assignFeatures(ctr: Function, features: FeatureConfigsMap): Promise<void>;
686
662
  }
687
663
  }
688
664
 
package/assignGingerly.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { normalizeAliasOptions } from './resolve/getValues.js';
2
+ const DEFAULT_ENHANCEMENT_KEY = Symbol('assign-gingerly.default-enhancement-setup');
2
3
  /**
3
4
  * GUID for global instance map storage to ensure uniqueness across package versions
4
5
  */
@@ -34,6 +35,7 @@ export class EnhancementRegisteredEvent extends Event {
34
35
  */
35
36
  export class EnhancementRegistry extends EventTarget {
36
37
  #items = new Set();
38
+ #pendingSetups = new Map();
37
39
  push(items) {
38
40
  if (Array.isArray(items)) {
39
41
  items.forEach(item => this.#items.add(item));
@@ -43,11 +45,12 @@ export class EnhancementRegistry extends EventTarget {
43
45
  }
44
46
  // Dispatch event after adding items
45
47
  this.dispatchEvent(new EnhancementRegisteredEvent(items));
46
- // Process features if present (fire-and-forget, uses shared featuresRegistry)
48
+ // Process features if present (async, tracked so callers can await)
47
49
  const itemsArr = Array.isArray(items) ? items : [items];
48
50
  for (const item of itemsArr) {
49
51
  if (item.features) {
50
- this.#assignFeatures(item.spawn, item.features);
52
+ const promise = this.#assignFeatures(item.spawn, item.features);
53
+ this._trackSetup(item.enhKey ?? DEFAULT_ENHANCEMENT_KEY, promise);
51
54
  }
52
55
  }
53
56
  }
@@ -56,8 +59,39 @@ export class EnhancementRegistry extends EventTarget {
56
59
  const featuresRegistry = this._featuresRegistry
57
60
  ?? (typeof customElements !== 'undefined' ? customElements.featuresRegistry : undefined);
58
61
  if (featuresRegistry) {
59
- assignFeatures(spawn, features, featuresRegistry);
62
+ await assignFeatures(spawn, features, featuresRegistry);
63
+ }
64
+ }
65
+ /**
66
+ * Wait for all pending setups for a given enhancement key to complete.
67
+ * @param enhKey - Enhancement key to wait for
68
+ */
69
+ async whenDefined(enhKey) {
70
+ const pending = this.#pendingSetups.get(enhKey);
71
+ if (pending && pending.length > 0) {
72
+ await Promise.all(pending);
73
+ }
74
+ }
75
+ /**
76
+ * Internal method to track a pending setup.
77
+ * @param name - Setup key
78
+ * @param promise - Promise representing the setup operation
79
+ */
80
+ _trackSetup(name, promise) {
81
+ if (!this.#pendingSetups.has(name)) {
82
+ this.#pendingSetups.set(name, []);
60
83
  }
84
+ this.#pendingSetups.get(name).push(promise);
85
+ // Clean up after completion
86
+ promise.finally(() => {
87
+ const pending = this.#pendingSetups.get(name);
88
+ if (pending) {
89
+ const index = pending.indexOf(promise);
90
+ if (index > -1) {
91
+ pending.splice(index, 1);
92
+ }
93
+ }
94
+ });
61
95
  }
62
96
  getItems() {
63
97
  return Array.from(this.#items);
@@ -105,9 +139,10 @@ export class ItemscopeRegistry extends EventTarget {
105
139
  }
106
140
  this.#configs.set(name, config);
107
141
  this.dispatchEvent(new Event(name));
108
- // Process features if present (fire-and-forget, uses shared featuresRegistry)
142
+ // Process features if present (async, tracked so callers can await)
109
143
  if (config.features) {
110
- this.#assignFeatures(config.manager, config.features);
144
+ const promise = this.#assignFeatures(config.manager, config.features);
145
+ this._trackSetup(name, promise);
111
146
  }
112
147
  }
113
148
  async #assignFeatures(manager, features) {
@@ -115,7 +150,7 @@ export class ItemscopeRegistry extends EventTarget {
115
150
  const featuresRegistry = this._featuresRegistry
116
151
  ?? (typeof customElements !== 'undefined' ? customElements.featuresRegistry : undefined);
117
152
  if (featuresRegistry) {
118
- assignFeatures(manager, features, featuresRegistry);
153
+ await assignFeatures(manager, features, featuresRegistry);
119
154
  }
120
155
  }
121
156
  /**
package/assignGingerly.ts CHANGED
@@ -1,10 +1,12 @@
1
1
 
2
2
 
3
- import { EnhancementConfig } from "./types/assign-gingerly/types";
3
+ import { EnhancementConfig, EnhKey } from "./types/assign-gingerly/types";
4
4
  import type { AssignFromOptions, FeatureConfigsMap, IAssignGingerlyOptions } from "./types/assign-gingerly/types";
5
5
  import type { PermissionProcessor } from './types/assign-gingerly/types.js';
6
6
  import { normalizeAliasOptions } from './resolve/getValues.js';
7
7
 
8
+ const DEFAULT_ENHANCEMENT_KEY = Symbol('assign-gingerly.default-enhancement-setup');
9
+
8
10
  /**
9
11
  * Constructor signature for ItemScope Manager classes
10
12
  */
@@ -72,6 +74,7 @@ export class EnhancementRegisteredEvent extends Event {
72
74
  */
73
75
  export class EnhancementRegistry extends EventTarget {
74
76
  #items: Set<EnhancementConfig> = new Set();
77
+ #pendingSetups = new Map<EnhKey, Promise<void>[]>();
75
78
 
76
79
  push(items: EnhancementConfig | EnhancementConfig[]): void {
77
80
  if (Array.isArray(items)) {
@@ -83,11 +86,12 @@ export class EnhancementRegistry extends EventTarget {
83
86
  // Dispatch event after adding items
84
87
  this.dispatchEvent(new EnhancementRegisteredEvent(items));
85
88
 
86
- // Process features if present (fire-and-forget, uses shared featuresRegistry)
89
+ // Process features if present (async, tracked so callers can await)
87
90
  const itemsArr = Array.isArray(items) ? items : [items];
88
91
  for (const item of itemsArr) {
89
92
  if (item.features) {
90
- this.#assignFeatures(item.spawn, item.features);
93
+ const promise = this.#assignFeatures(item.spawn, item.features);
94
+ this._trackSetup(item.enhKey ?? DEFAULT_ENHANCEMENT_KEY, promise);
91
95
  }
92
96
  }
93
97
  }
@@ -97,8 +101,42 @@ export class EnhancementRegistry extends EventTarget {
97
101
  const featuresRegistry = (this as any)._featuresRegistry
98
102
  ?? (typeof customElements !== 'undefined' ? (customElements as any).featuresRegistry : undefined);
99
103
  if (featuresRegistry) {
100
- assignFeatures(spawn, features, featuresRegistry);
104
+ await assignFeatures(spawn, features, featuresRegistry);
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Wait for all pending setups for a given enhancement key to complete.
110
+ * @param enhKey - Enhancement key to wait for
111
+ */
112
+ async whenDefined(enhKey: EnhKey): Promise<void> {
113
+ const pending = this.#pendingSetups.get(enhKey);
114
+ if (pending && pending.length > 0) {
115
+ await Promise.all(pending);
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Internal method to track a pending setup.
121
+ * @param name - Setup key
122
+ * @param promise - Promise representing the setup operation
123
+ */
124
+ _trackSetup(name: EnhKey, promise: Promise<void>): void {
125
+ if (!this.#pendingSetups.has(name)) {
126
+ this.#pendingSetups.set(name, []);
101
127
  }
128
+ this.#pendingSetups.get(name)!.push(promise);
129
+
130
+ // Clean up after completion
131
+ promise.finally(() => {
132
+ const pending = this.#pendingSetups.get(name);
133
+ if (pending) {
134
+ const index = pending.indexOf(promise);
135
+ if (index > -1) {
136
+ pending.splice(index, 1);
137
+ }
138
+ }
139
+ });
102
140
  }
103
141
 
104
142
  getItems(): EnhancementConfig[] {
@@ -151,9 +189,10 @@ export class ItemscopeRegistry extends EventTarget {
151
189
  this.#configs.set(name, config);
152
190
  this.dispatchEvent(new Event(name));
153
191
 
154
- // Process features if present (fire-and-forget, uses shared featuresRegistry)
192
+ // Process features if present (async, tracked so callers can await)
155
193
  if ((config as any).features) {
156
- this.#assignFeatures(config.manager, (config as any).features);
194
+ const promise = this.#assignFeatures(config.manager, (config as any).features);
195
+ this._trackSetup(name, promise);
157
196
  }
158
197
  }
159
198
 
@@ -162,7 +201,7 @@ export class ItemscopeRegistry extends EventTarget {
162
201
  const featuresRegistry = (this as any)._featuresRegistry
163
202
  ?? (typeof customElements !== 'undefined' ? (customElements as any).featuresRegistry : undefined);
164
203
  if (featuresRegistry) {
165
- assignFeatures(manager, features, featuresRegistry);
204
+ await assignFeatures(manager, features, featuresRegistry);
166
205
  }
167
206
  }
168
207
 
@@ -484,6 +484,8 @@ export declare class EnhancementRegistry extends EventTarget {
484
484
  getItems(): EnhancementConfig[];
485
485
  findBySymbol(symbol: symbol | string): EnhancementConfig | undefined;
486
486
  findByEnhKey(enhKey: string | symbol): EnhancementConfig | undefined;
487
+ whenDefined(enhKey: string | symbol): Promise<void>;
488
+ _trackSetup(name: string | symbol, promise: Promise<void>): void;
487
489
  }
488
490
 
489
491
  /**
@@ -652,7 +654,7 @@ export declare function assignFeatures(
652
654
  ctr: Function,
653
655
  features: FeatureConfigsMap,
654
656
  featuresRegistry: FeaturesRegistry
655
- ): Promise<void> | undefined;
657
+ ): Promise<void>;
656
658
 
657
659
  /**
658
660
  * Captures own-properties that shadow feature getters.
@@ -0,0 +1,15 @@
1
+ export interface SimpleWCInfo<TProps = any, TPublicMethods = any>{
2
+ tagName: string;
3
+ cssParts?: {[key: string]: string};
4
+ props?: any;
5
+ methods?: any;
6
+ nonAttribProps?: (keyof TProps)[];
7
+ cssProps?: {[key: string]: string};
8
+ slots?: {[key: string]: string};
9
+ events?: {[key: string]: string};
10
+ name: string,
11
+ description: string,
12
+ homepage: string,
13
+ license: string,
14
+
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assign-gingerly",
3
- "version": "0.0.76",
3
+ "version": "0.0.78",
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": {
@@ -484,6 +484,8 @@ export declare class EnhancementRegistry extends EventTarget {
484
484
  getItems(): EnhancementConfig[];
485
485
  findBySymbol(symbol: symbol | string): EnhancementConfig | undefined;
486
486
  findByEnhKey(enhKey: string | symbol): EnhancementConfig | undefined;
487
+ whenDefined(enhKey: string | symbol): Promise<void>;
488
+ _trackSetup(name: string | symbol, promise: Promise<void>): void;
487
489
  }
488
490
 
489
491
  /**
@@ -652,7 +654,7 @@ export declare function assignFeatures(
652
654
  ctr: Function,
653
655
  features: FeatureConfigsMap,
654
656
  featuresRegistry: FeaturesRegistry
655
- ): Promise<void> | undefined;
657
+ ): Promise<void>;
656
658
 
657
659
  /**
658
660
  * Captures own-properties that shadow feature getters.