assign-gingerly 0.0.63 → 0.0.65
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 +59 -18
- package/assignFrom.js +21 -19
- package/assignFrom.ts +26 -24
- package/assignFromAsync.js +10 -7
- package/assignFromAsync.ts +13 -96
- package/assignGingerly.js +3 -17
- package/assignGingerly.ts +10 -18
- package/assignTentatively.ts +3 -4
- package/getValues.js +81 -25
- package/getValues.ts +85 -26
- package/handlers/arr.js +13 -0
- package/handlers/arr.ts +13 -0
- package/handlers/manageTemplateList.js +1 -1
- package/handlers/manageTemplateList.ts +1 -1
- package/handlers/nudge.js +23 -0
- package/handlers/nudge.ts +23 -0
- package/index.js +2 -0
- package/index.ts +2 -0
- package/inferencer/types/assign-gingerly/types.d.ts +269 -1
- package/inferencer/types/mount-observer/types.d.ts +10 -2
- package/inferencer/types/roundabout/types.d.ts +1 -1
- package/inferencer/types/three-peat/types.d.ts +18 -0
- package/object-extension.js +1 -1
- package/object-extension.ts +4 -3
- package/package.json +9 -1
- package/paths.ts +1 -1
- package/{withIdsCorrector.js → pinCorrector.js} +5 -5
- package/{withIdsCorrector.ts → pinCorrector.ts} +5 -5
- package/processHandlerCommands.js +4 -2
- package/processHandlerCommands.ts +4 -2
- package/resolveIdRef.js +8 -8
- package/resolveIdRef.ts +9 -9
- package/resolveValues.js +20 -88
- package/resolveValues.ts +17 -91
- package/types/assign-gingerly/types.d.ts +168 -0
|
@@ -261,6 +261,149 @@ export interface IAssignGingerlyOptions {
|
|
|
261
261
|
signal?: AbortSignal;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Options for assignTentatively — reversible assignment with change tracking.
|
|
266
|
+
*
|
|
267
|
+
* Supports a subset of assignGingerly's path features (nested paths, +=, =!, -=)
|
|
268
|
+
* with the addition of reversal tracking.
|
|
269
|
+
*/
|
|
270
|
+
export interface IAssignTentativelyOptions {
|
|
271
|
+
/**
|
|
272
|
+
* Object to accumulate reversal entries into.
|
|
273
|
+
* If omitted, a new object is created internally.
|
|
274
|
+
* Pass an existing object to accumulate reversals across multiple calls.
|
|
275
|
+
*
|
|
276
|
+
* The reversal object can be passed to assignGingerly to undo all changes:
|
|
277
|
+
* @example
|
|
278
|
+
* const reversal = {};
|
|
279
|
+
* assignTentatively(obj, { name: 'Bob' }, { reversal });
|
|
280
|
+
* // Later:
|
|
281
|
+
* assignGingerly(obj, reversal); // restores name to original value
|
|
282
|
+
*/
|
|
283
|
+
reversal?: Record<string | symbol, any>;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Alias mappings for property and method names.
|
|
287
|
+
* Same semantics as IAssignGingerlyOptions.aka — substituted before path evaluation.
|
|
288
|
+
*/
|
|
289
|
+
aka?: Record<string, string>;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Options for assignFrom / assignFromAsync.
|
|
294
|
+
*/
|
|
295
|
+
export interface AssignFromOptions {
|
|
296
|
+
/** Source object to resolve RHS path strings against */
|
|
297
|
+
from: any;
|
|
298
|
+
|
|
299
|
+
/** Protocol handlers (sync or async) */
|
|
300
|
+
protocols?: Record<string, (key: string) => any | Promise<any>>;
|
|
301
|
+
|
|
302
|
+
/** Method names to call during path evaluation */
|
|
303
|
+
withMethods?: string[] | Set<string>;
|
|
304
|
+
|
|
305
|
+
/** Alias mappings for path segments */
|
|
306
|
+
aka?: Record<string, string>;
|
|
307
|
+
|
|
308
|
+
/** AbortSignal for cleanup */
|
|
309
|
+
signal?: AbortSignal;
|
|
310
|
+
|
|
311
|
+
/** Loop variable bindings — expand pattern entries containing ${x} */
|
|
312
|
+
where_x_in?: string[];
|
|
313
|
+
/** Loop variable bindings — expand pattern entries containing ${y} */
|
|
314
|
+
where_y_in?: string[];
|
|
315
|
+
/** Loop variable bindings — expand pattern entries containing ${z} */
|
|
316
|
+
where_z_in?: string[];
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Pin element references by variable name.
|
|
320
|
+
* Used with `#[varName]` syntax in LHS keys for fast repeated element access.
|
|
321
|
+
*
|
|
322
|
+
* - String value: existing element ID (uses getElementById)
|
|
323
|
+
* - Object value: { qry: 'selector' } — finds element via querySelector on target, auto-assigns an ID
|
|
324
|
+
* - Object value: { path: [...], expect?, fallback? } — child index path + auto-ID + optional validation
|
|
325
|
+
*/
|
|
326
|
+
pin?: Record<string, string | { qry: string } | { path: number[]; expect?: string; fallback?: boolean }>;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Positional element references for use with `#[varName]` syntax.
|
|
330
|
+
* Resolves elements by child index path — no IDs assigned, no caching.
|
|
331
|
+
*/
|
|
332
|
+
at?: Record<string, number[] | { path: number[]; expect?: string; fallback?: boolean }>;
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Handler implementations scoped to this call.
|
|
336
|
+
* Key: the `do` name referenced in handler configs.
|
|
337
|
+
* Value: a class constructor, an import path, or a builtIns.* alias string.
|
|
338
|
+
*/
|
|
339
|
+
handlers?: Record<string, AssignFromHandlerConstructor | string>;
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Inferred assignments — automatically distribute source values to matching
|
|
343
|
+
* DOM elements based on structural conventions (itemprop, name, etc.).
|
|
344
|
+
*/
|
|
345
|
+
infer?: {
|
|
346
|
+
byItemprop?: string[] | true;
|
|
347
|
+
'|'?: string[] | true;
|
|
348
|
+
byName?: string[] | true | { props: string[] | true; outside: string };
|
|
349
|
+
'@'?: string[] | true | { props: string[] | true; outside: string };
|
|
350
|
+
beVigilant?: boolean;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Bulk enhancement application via EMC JSON configs.
|
|
355
|
+
*/
|
|
356
|
+
enhance?: Array<{ emc: string; matching?: string; parse?: boolean }>;
|
|
357
|
+
|
|
358
|
+
/** Registry for enhancement dependency injection (inherited from IAssignGingerlyOptions) */
|
|
359
|
+
registry?: any;
|
|
360
|
+
|
|
361
|
+
[key: string]: any;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Options for synchronous value resolution (getValues / getValue).
|
|
366
|
+
* Extends IAssignGingerlyOptions with synchronous protocol handlers.
|
|
367
|
+
*/
|
|
368
|
+
export interface GetValuesOptions extends IAssignGingerlyOptions {
|
|
369
|
+
/**
|
|
370
|
+
* Internal root object for special $0 references.
|
|
371
|
+
* This is used by assignFrom to resolve values relative to the target object.
|
|
372
|
+
*/
|
|
373
|
+
root?: any;
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Synchronous protocol handlers for resolving protocol-prefixed values.
|
|
377
|
+
* Each handler receives the key portion and MUST return synchronously.
|
|
378
|
+
* For async protocols, use ResolveValuesOptions / resolveValues instead.
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* protocols: {
|
|
382
|
+
* globalThis: (key) => globalThis[key],
|
|
383
|
+
* localStorage: (key) => JSON.parse(localStorage.getItem(key) || 'null')
|
|
384
|
+
* }
|
|
385
|
+
*/
|
|
386
|
+
protocols?: Record<string, (key: string) => any>;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Options for async value resolution (resolveValues).
|
|
391
|
+
* Same as GetValuesOptions but protocol handlers may return Promises.
|
|
392
|
+
*/
|
|
393
|
+
export interface ResolveValuesOptions extends IAssignGingerlyOptions {
|
|
394
|
+
/**
|
|
395
|
+
* Internal root object for special $0 references.
|
|
396
|
+
* This is used by assignFrom to resolve values relative to the target object.
|
|
397
|
+
*/
|
|
398
|
+
root?: any;
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Protocol handlers for resolving protocol-prefixed values (e.g., 'globalThis://key').
|
|
402
|
+
* Each handler receives the key portion and returns the resolved value (sync or async).
|
|
403
|
+
*/
|
|
404
|
+
protocols?: Record<string, (key: string) => any | Promise<any>>;
|
|
405
|
+
}
|
|
406
|
+
|
|
264
407
|
/**
|
|
265
408
|
* Event dispatched when enhancement configs are registered
|
|
266
409
|
*/
|
|
@@ -538,15 +681,140 @@ export interface LazyLoadConfig extends HandlerConfig {
|
|
|
538
681
|
if: string;
|
|
539
682
|
/** Template element to clone (resolved via protocol or path) */
|
|
540
683
|
instantiate: string;
|
|
541
|
-
/** Insert method: 'appendChild' (default) or '
|
|
684
|
+
/** Insert method: 'appendChild' (default), 'prepend', or 'after' (sibling after target) */
|
|
542
685
|
method?: string;
|
|
543
686
|
/** If true, removes nodes when hiding instead of adding hidden attribute */
|
|
544
687
|
forget?: boolean | string;
|
|
688
|
+
/** Enable view transitions */
|
|
689
|
+
transitional?: boolean | string;
|
|
690
|
+
/** CSS class for hiding (default: 'ag-hide', only used when transitional: true) */
|
|
691
|
+
hideClass?: string;
|
|
692
|
+
/** Custom CSS for the hide class (default: 'display: none') */
|
|
693
|
+
hideCss?: string;
|
|
545
694
|
/** Optional async callback invoked after cloning, resolved from the VM */
|
|
546
695
|
onInstantiated?: string;
|
|
696
|
+
/** Override auto-derived marker name */
|
|
697
|
+
markerName?: string;
|
|
698
|
+
/** Set inert attribute on hidden elements */
|
|
699
|
+
toggleInert?: boolean | string;
|
|
700
|
+
/** Set disabled property on hidden form elements */
|
|
701
|
+
toggleDisabled?: boolean | string;
|
|
547
702
|
};
|
|
548
703
|
}
|
|
549
704
|
|
|
705
|
+
/**
|
|
706
|
+
* Resolved parameters received by LazyLoadHandler.assign() after resolveValues processing.
|
|
707
|
+
*/
|
|
708
|
+
export interface LazyLoadResolvedParams {
|
|
709
|
+
/** Condition — resolved to actual truthy/falsy value */
|
|
710
|
+
if: any;
|
|
711
|
+
/** Template element — resolved to HTMLTemplateElement or DocumentFragment */
|
|
712
|
+
instantiate: HTMLTemplateElement | DocumentFragment;
|
|
713
|
+
/** Insertion method (default: 'appendChild') */
|
|
714
|
+
method?: 'appendChild' | 'prepend' | 'after';
|
|
715
|
+
/** Remove nodes on hide instead of using hidden attribute */
|
|
716
|
+
forget?: boolean;
|
|
717
|
+
/** Enable view transitions */
|
|
718
|
+
transitional?: boolean;
|
|
719
|
+
/** CSS class for hiding (default: 'ag-hide', only used when transitional: true) */
|
|
720
|
+
hideClass?: string;
|
|
721
|
+
/** Custom CSS for the hide class (default: 'display: none') */
|
|
722
|
+
hideCss?: string;
|
|
723
|
+
/** Callback after clone+insert */
|
|
724
|
+
onInstantiated?: (ctx: LazyLoadInstantiatedContext) => void | Promise<void>;
|
|
725
|
+
/** Override auto-derived marker name */
|
|
726
|
+
markerName?: string;
|
|
727
|
+
/** Set inert attribute on hidden elements (removes from a11y tree + interaction) */
|
|
728
|
+
toggleInert?: boolean;
|
|
729
|
+
/** Set disabled property on hidden form elements */
|
|
730
|
+
toggleDisabled?: boolean;
|
|
731
|
+
/** Name of a pre-existing marker pair whose content should be removed on first activation.
|
|
732
|
+
* Used for SSR placeholder content (e.g., "Loading..." text) that disappears once real content loads. */
|
|
733
|
+
placeholder?: string;
|
|
734
|
+
/** Assignment config applied to cloned content before insertion.
|
|
735
|
+
* Same shape as manageTemplateList's fromEachItem: { assignToFragment, withOptions } or { configs: [...] } */
|
|
736
|
+
assign?: {
|
|
737
|
+
assignToFragment?: Record<string, any>;
|
|
738
|
+
withOptions?: Record<string, any>;
|
|
739
|
+
configs?: Array<{ assignToFragment?: Record<string, any>; withOptions?: Record<string, any> }>;
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* Configuration for the builtIns.lazyLoadSwitch handler.
|
|
745
|
+
*/
|
|
746
|
+
export interface LazyLoadSwitchConfig extends HandlerConfig {
|
|
747
|
+
do: 'builtIns.lazyLoadSwitch';
|
|
748
|
+
resolve: {
|
|
749
|
+
/** Left-hand side of comparison (resolved from VM) */
|
|
750
|
+
lhs: string;
|
|
751
|
+
/** Comparison operator (default: '===') */
|
|
752
|
+
op?: '===' | '!==' | '==' | '!=' | '<' | '>' | '<=' | '>=';
|
|
753
|
+
/** Right-hand side of comparison (resolved from VM or literal) */
|
|
754
|
+
rhs: string;
|
|
755
|
+
/** Template element to clone (resolved via protocol or path) */
|
|
756
|
+
instantiate: string;
|
|
757
|
+
/** Insert method: 'appendChild' (default), 'prepend', or 'after' */
|
|
758
|
+
method?: string;
|
|
759
|
+
/** If true, removes nodes when hiding instead of adding hidden attribute */
|
|
760
|
+
forget?: boolean | string;
|
|
761
|
+
/** Enable view transitions */
|
|
762
|
+
transitional?: boolean | string;
|
|
763
|
+
/** CSS class for hiding (default: 'ag-hide', only used when transitional: true) */
|
|
764
|
+
hideClass?: string;
|
|
765
|
+
/** Custom CSS for the hide class (default: 'display: none') */
|
|
766
|
+
hideCss?: string;
|
|
767
|
+
/** Optional async callback invoked after cloning, resolved from the VM */
|
|
768
|
+
onInstantiated?: string;
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Resolved parameters received by LazyLoadSwitchHandler.assign() after resolveValues processing.
|
|
774
|
+
*/
|
|
775
|
+
export interface LazyLoadSwitchResolvedParams extends Omit<LazyLoadResolvedParams, 'if'> {
|
|
776
|
+
/** Left-hand side — resolved to actual value */
|
|
777
|
+
lhs: any;
|
|
778
|
+
/** Comparison operator (default: '===') */
|
|
779
|
+
op?: '===' | '!==' | '==' | '!=' | '<' | '>' | '<=' | '>=';
|
|
780
|
+
/** Right-hand side — resolved to actual value */
|
|
781
|
+
rhs: any;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
export interface FromEachItemConfig {
|
|
785
|
+
assignToFragment?: Record<string, any>;
|
|
786
|
+
withOptions?: AssignFromOptions;
|
|
787
|
+
resolve?: {
|
|
788
|
+
key?: string;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
export interface ManageTemplateListConfig extends HandlerConfig {
|
|
793
|
+
do: 'builtIns.manageTemplateList';
|
|
794
|
+
resolve: ManageTemplateListResolvedParams;
|
|
795
|
+
fromEachItem: FromEachItemConfig;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Resolved parameters received by ManageTemplateListHandler.assign().
|
|
800
|
+
*/
|
|
801
|
+
export interface ManageTemplateListResolvedParams {
|
|
802
|
+
/** The iterable to loop over (resolved from VM) */
|
|
803
|
+
forEach: Iterable<any>;
|
|
804
|
+
/** Template element to clone per item */
|
|
805
|
+
instantiate: HTMLTemplateElement | DocumentFragment;
|
|
806
|
+
/** Insertion method (default: 'appendChild') */
|
|
807
|
+
method?: 'appendChild' | 'prepend' | 'after';
|
|
808
|
+
/** Remove nodes on hide instead of using hidden attribute */
|
|
809
|
+
forget?: boolean;
|
|
810
|
+
/** Override auto-derived marker name */
|
|
811
|
+
markerName?: string;
|
|
812
|
+
/** Wait for async rendering before DOM commit */
|
|
813
|
+
waitForSettled?: boolean | { idleMs?: number; timeout?: number };
|
|
814
|
+
/** Yield to browser every N items to prevent jank (default: undefined = no yielding) */
|
|
815
|
+
yieldEvery?: number;
|
|
816
|
+
}
|
|
817
|
+
|
|
550
818
|
/**
|
|
551
819
|
* Context passed to onInstantiated callbacks after template cloning.
|
|
552
820
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Core types for MountObserver v2 - Polyfill Supported Scenario I
|
|
2
2
|
|
|
3
|
-
import {EnhancementConfigBase, EnhKey, AttrPatterns} from '../assign-gingerly/types';
|
|
3
|
+
import {EnhancementConfigBase, EnhKey, AttrPatterns, AssignFromOptions} from '../assign-gingerly/types';
|
|
4
4
|
|
|
5
5
|
export type Constructor = new (...args: any[]) => any;
|
|
6
6
|
|
|
@@ -189,6 +189,14 @@ export interface MountConfig<TKeys extends string = string, TCustomData = unknow
|
|
|
189
189
|
*/
|
|
190
190
|
stageOnMount?: Record<string, any>;
|
|
191
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Options passed to assign-gingerly for assignOnMount, assignOnDismount, and stageOnMount.
|
|
194
|
+
* Enables features like method calls (withMethods), aliases (aka), async methods, and signal-based cleanup.
|
|
195
|
+
* Shared across all assign operations on this observer.
|
|
196
|
+
* @example { withMethods: ['setAttribute', 'removeAttribute'], aka: { '$': 'querySelector' } }
|
|
197
|
+
*/
|
|
198
|
+
assignOptions?: Record<string, any>;
|
|
199
|
+
|
|
192
200
|
/**
|
|
193
201
|
* When true, enables detailed event dispatching for debugging and monitoring.
|
|
194
202
|
* Provides granular lifecycle events for observation.
|
|
@@ -342,7 +350,7 @@ export interface IMountObserver extends EventTarget {
|
|
|
342
350
|
observe(observedNode: Node): Promise<void>;
|
|
343
351
|
disconnect(): void;
|
|
344
352
|
disconnectedSignal: AbortSignal;
|
|
345
|
-
|
|
353
|
+
assign(config: Record<string, any> | undefined, options?: Record<string, any>): Promise<void>;
|
|
346
354
|
getNotifier(element: Element): EventTarget;
|
|
347
355
|
readonly options: MountObserverOptions;
|
|
348
356
|
}
|
|
@@ -190,7 +190,7 @@ export interface RoundaboutOptions<TProps = unknown, TActions = TProps, ETProps
|
|
|
190
190
|
* Options passed to every internal assignGingerly call.
|
|
191
191
|
* See IAssignGingerlyOptions in assign-gingerly for details.
|
|
192
192
|
*/
|
|
193
|
-
|
|
193
|
+
assignOptions?: import('../assign-gingerly/types.js').IAssignGingerlyOptions,
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
196
|
* Protocol handlers for resolving protocol-prefixed values in initialPropVals.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ElementEnhancementGateway, SpawnContext, FromEachItemConfig } from "../assign-gingerly/types";
|
|
2
|
+
|
|
3
|
+
export interface EndUserProps{
|
|
4
|
+
/**
|
|
5
|
+
* Property of host to pull list from.
|
|
6
|
+
* If not provided, the host itself is
|
|
7
|
+
* assumed to be iterable.
|
|
8
|
+
*/
|
|
9
|
+
listProp?: string,
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Specify id of peer element to pull list from.
|
|
13
|
+
*/
|
|
14
|
+
src?: string;
|
|
15
|
+
each: FromEachItemConfig,
|
|
16
|
+
target: string,
|
|
17
|
+
updateOn: string,
|
|
18
|
+
}
|
package/object-extension.js
CHANGED
|
@@ -432,7 +432,7 @@ Object.defineProperty(Object.prototype, 'assignGingerly', {
|
|
|
432
432
|
Object.defineProperty(Object.prototype, 'assignTentatively', {
|
|
433
433
|
value: function (source, options) {
|
|
434
434
|
const reversal = options?.reversal ?? {};
|
|
435
|
-
assignTentatively(this, source, { reversal });
|
|
435
|
+
assignTentatively(this, source, { ...options, reversal });
|
|
436
436
|
return reversal;
|
|
437
437
|
},
|
|
438
438
|
writable: true,
|
package/object-extension.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import assignGingerly, { EnhancementRegistry, ItemscopeRegistry, IAssignGingerlyOptions, getInstanceMap, INSTANCE_MAP_GUID } from './assignGingerly.js';
|
|
2
2
|
import assignTentatively from './assignTentatively.js';
|
|
3
|
+
import type { IAssignTentativelyOptions } from './types/assign-gingerly/types.js';
|
|
3
4
|
import { EnhancementConfig, SpawnContext } from './types/assign-gingerly/types.js';
|
|
4
5
|
import { parseWithAttrs } from './parseWithAttrs.js';
|
|
5
6
|
|
|
@@ -77,7 +78,7 @@ declare global {
|
|
|
77
78
|
*/
|
|
78
79
|
assignTentatively(
|
|
79
80
|
source: Record<string | symbol, any>,
|
|
80
|
-
options?:
|
|
81
|
+
options?: IAssignTentativelyOptions
|
|
81
82
|
): Record<string | symbol, any>;
|
|
82
83
|
}
|
|
83
84
|
}
|
|
@@ -576,10 +577,10 @@ Object.defineProperty(Object.prototype, 'assignTentatively', {
|
|
|
576
577
|
value: function <T extends object>(
|
|
577
578
|
this: T,
|
|
578
579
|
source: Record<string | symbol, any>,
|
|
579
|
-
options?:
|
|
580
|
+
options?: IAssignTentativelyOptions
|
|
580
581
|
): Record<string | symbol, any> {
|
|
581
582
|
const reversal = options?.reversal ?? {};
|
|
582
|
-
assignTentatively(this, source, { reversal });
|
|
583
|
+
assignTentatively(this, source, { ...options, reversal });
|
|
583
584
|
return reversal;
|
|
584
585
|
},
|
|
585
586
|
writable: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "assign-gingerly",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.65",
|
|
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": {
|
|
@@ -169,6 +169,14 @@
|
|
|
169
169
|
"./evaluatePathWithAsyncMethods.js": {
|
|
170
170
|
"default": "./evaluatePathWithAsyncMethods.js",
|
|
171
171
|
"types": "./evaluatePathWithAsyncMethods.ts"
|
|
172
|
+
},
|
|
173
|
+
"./handlers/nudge.js": {
|
|
174
|
+
"default": "./handlers/nudge.js",
|
|
175
|
+
"types": "./handlers/nudge.ts"
|
|
176
|
+
},
|
|
177
|
+
"./handlers/arr.js": {
|
|
178
|
+
"default": "./handlers/arr.js",
|
|
179
|
+
"types": "./handlers/arr.ts"
|
|
172
180
|
}
|
|
173
181
|
},
|
|
174
182
|
"main": "index.js",
|
package/paths.ts
CHANGED
|
@@ -287,7 +287,7 @@ export function doAssign(...pairs: Record<string, any>[]): { assign: Record<stri
|
|
|
287
287
|
* const merges = [
|
|
288
288
|
* ...forEachKeyIn<Person>(['firstName', 'lastName'], (key, $) => ({
|
|
289
289
|
* ifKeyIn: [key],
|
|
290
|
-
* assignOptions: {
|
|
290
|
+
* assignOptions: { pin: { [key]: { qry: `[name="${key}"]` } } },
|
|
291
291
|
* ...doAssign(set($['#' + key]).to($[key]))
|
|
292
292
|
* })),
|
|
293
293
|
* ];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* pinCorrector.ts — Dev-time diagnostic for stale pin coordinates.
|
|
3
3
|
*
|
|
4
4
|
* Dynamically imported only on mismatch — zero cost in production or when coordinates are correct.
|
|
5
5
|
* Computes and logs the correct child index path for a given selector.
|
|
@@ -24,24 +24,24 @@ function computeChildPath(root, target) {
|
|
|
24
24
|
return current === root ? path : null;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* Log a correction suggestion for a mismatched
|
|
27
|
+
* Log a correction suggestion for a mismatched pin config.
|
|
28
28
|
*/
|
|
29
29
|
export function logConfigCorrection(target, varName, config) {
|
|
30
30
|
if (!config.expect)
|
|
31
31
|
return;
|
|
32
32
|
const correctEl = target.querySelector?.(config.expect);
|
|
33
33
|
if (!correctEl) {
|
|
34
|
-
console.warn(`
|
|
34
|
+
console.warn(`pin["${varName}"]: path [${config.path}] did not match "${config.expect}" ` +
|
|
35
35
|
`and querySelector also found no match. Check that the selector is correct.`);
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
const correctPath = computeChildPath(target, correctEl);
|
|
39
39
|
if (correctPath) {
|
|
40
|
-
console.warn(`
|
|
40
|
+
console.warn(`pin["${varName}"]: path [${config.path}] did not match "${config.expect}". ` +
|
|
41
41
|
`Suggested correction: [${correctPath.join(', ')}]`);
|
|
42
42
|
}
|
|
43
43
|
else {
|
|
44
|
-
console.warn(`
|
|
44
|
+
console.warn(`pin["${varName}"]: path [${config.path}] did not match "${config.expect}". ` +
|
|
45
45
|
`Could not compute a child index path (element may not be a descendant of target).`);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* pinCorrector.ts — Dev-time diagnostic for stale pin coordinates.
|
|
3
3
|
*
|
|
4
4
|
* Dynamically imported only on mismatch — zero cost in production or when coordinates are correct.
|
|
5
5
|
* Computes and logs the correct child index path for a given selector.
|
|
@@ -26,7 +26,7 @@ function computeChildPath(root: Element, target: Element): number[] | null {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
* Log a correction suggestion for a mismatched
|
|
29
|
+
* Log a correction suggestion for a mismatched pin config.
|
|
30
30
|
*/
|
|
31
31
|
export function logConfigCorrection(
|
|
32
32
|
target: any,
|
|
@@ -38,7 +38,7 @@ export function logConfigCorrection(
|
|
|
38
38
|
const correctEl = target.querySelector?.(config.expect);
|
|
39
39
|
if (!correctEl) {
|
|
40
40
|
console.warn(
|
|
41
|
-
`
|
|
41
|
+
`pin["${varName}"]: path [${config.path}] did not match "${config.expect}" ` +
|
|
42
42
|
`and querySelector also found no match. Check that the selector is correct.`
|
|
43
43
|
);
|
|
44
44
|
return;
|
|
@@ -47,12 +47,12 @@ export function logConfigCorrection(
|
|
|
47
47
|
const correctPath = computeChildPath(target, correctEl);
|
|
48
48
|
if (correctPath) {
|
|
49
49
|
console.warn(
|
|
50
|
-
`
|
|
50
|
+
`pin["${varName}"]: path [${config.path}] did not match "${config.expect}". ` +
|
|
51
51
|
`Suggested correction: [${correctPath.join(', ')}]`
|
|
52
52
|
);
|
|
53
53
|
} else {
|
|
54
54
|
console.warn(
|
|
55
|
-
`
|
|
55
|
+
`pin["${varName}"]: path [${config.path}] did not match "${config.expect}". ` +
|
|
56
56
|
`Could not compute a child index path (element may not be a descendant of target).`
|
|
57
57
|
);
|
|
58
58
|
}
|
|
@@ -194,7 +194,8 @@ export async function processHandlerCommands(target, handlerKeys, pattern, optio
|
|
|
194
194
|
resolvedParams = getValues(config.get, options.from, {
|
|
195
195
|
withMethods: options.withMethods,
|
|
196
196
|
aka: options.aka,
|
|
197
|
-
protocols: options.protocols
|
|
197
|
+
protocols: options.protocols,
|
|
198
|
+
root: target
|
|
198
199
|
});
|
|
199
200
|
}
|
|
200
201
|
// Resolve 'resolve' map asynchronously (yields to microtask queue)
|
|
@@ -202,7 +203,8 @@ export async function processHandlerCommands(target, handlerKeys, pattern, optio
|
|
|
202
203
|
const asyncResolved = await resolveValues(config.resolve, options.from, {
|
|
203
204
|
withMethods: options.withMethods,
|
|
204
205
|
aka: options.aka,
|
|
205
|
-
protocols: options.protocols
|
|
206
|
+
protocols: options.protocols,
|
|
207
|
+
root: target
|
|
206
208
|
});
|
|
207
209
|
Object.assign(resolvedParams, asyncResolved);
|
|
208
210
|
}
|
|
@@ -220,7 +220,8 @@ export async function processHandlerCommands(
|
|
|
220
220
|
resolvedParams = getValues(config.get, options.from, {
|
|
221
221
|
withMethods: options.withMethods,
|
|
222
222
|
aka: options.aka,
|
|
223
|
-
protocols: options.protocols
|
|
223
|
+
protocols: options.protocols,
|
|
224
|
+
root: target
|
|
224
225
|
});
|
|
225
226
|
}
|
|
226
227
|
// Resolve 'resolve' map asynchronously (yields to microtask queue)
|
|
@@ -228,7 +229,8 @@ export async function processHandlerCommands(
|
|
|
228
229
|
const asyncResolved = await resolveValues(config.resolve, options.from, {
|
|
229
230
|
withMethods: options.withMethods,
|
|
230
231
|
aka: options.aka,
|
|
231
|
-
protocols: options.protocols
|
|
232
|
+
protocols: options.protocols,
|
|
233
|
+
root: target
|
|
232
234
|
});
|
|
233
235
|
Object.assign(resolvedParams, asyncResolved);
|
|
234
236
|
}
|
package/resolveIdRef.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* resolveIdRef.ts — Cached element resolution via #[x] syntax.
|
|
3
3
|
*
|
|
4
|
-
* Dynamically imported by assignFrom when `
|
|
4
|
+
* Dynamically imported by assignFrom when `pin` is provided or `#[x]` patterns are detected.
|
|
5
5
|
* Provides lazy, WeakRef-cached element lookups keyed by variable name.
|
|
6
6
|
*
|
|
7
7
|
* First access: runs the query against the target, auto-assigns an ID if needed, caches via WeakRef.
|
|
@@ -37,11 +37,11 @@ function generateUniqueId(rootNode) {
|
|
|
37
37
|
*
|
|
38
38
|
* @param varName - The variable name (e.g., 'x' from '#[x]')
|
|
39
39
|
* @param target - The target element to query against
|
|
40
|
-
* @param
|
|
40
|
+
* @param pin - The pin configuration map
|
|
41
41
|
* @returns The resolved element, or undefined if not found
|
|
42
42
|
*/
|
|
43
|
-
export function resolveIdVariable(varName, target,
|
|
44
|
-
const config =
|
|
43
|
+
export function resolveIdVariable(varName, target, pin) {
|
|
44
|
+
const config = pin[varName];
|
|
45
45
|
if (config === undefined)
|
|
46
46
|
return undefined;
|
|
47
47
|
// For 'at' option path-based configs (array or { path }), resolve directly from target — no ID, no caching
|
|
@@ -56,10 +56,10 @@ export function resolveIdVariable(varName, target, withIds) {
|
|
|
56
56
|
return current instanceof Element ? current : undefined;
|
|
57
57
|
}
|
|
58
58
|
if (typeof config === 'object' && 'path' in config && !('qry' in config)) {
|
|
59
|
-
// Determine if this is from 'at' (no ID assignment) or '
|
|
60
|
-
// When called from 'at', we skip ID/caching. When from '
|
|
59
|
+
// Determine if this is from 'at' (no ID assignment) or 'pin' with path (assigns ID + caches)
|
|
60
|
+
// When called from 'at', we skip ID/caching. When from 'pin', we assign ID and cache.
|
|
61
61
|
// Distinguish by presence in the options — caller passes the merged map.
|
|
62
|
-
// For now: { path } without 'noId' → assign ID + cache (
|
|
62
|
+
// For now: { path } without 'noId' → assign ID + cache (pin behavior)
|
|
63
63
|
const rootNode = target.getRootNode?.() ?? target;
|
|
64
64
|
let current = target;
|
|
65
65
|
for (const idx of config.path) {
|
|
@@ -78,7 +78,7 @@ export function resolveIdVariable(varName, target, withIds) {
|
|
|
78
78
|
// Fire-and-forget: log correction suggestion
|
|
79
79
|
const capturedConfig = config;
|
|
80
80
|
const capturedVarName = varName;
|
|
81
|
-
import('./
|
|
81
|
+
import('./pinCorrector.js').then(module => {
|
|
82
82
|
module.logConfigCorrection(target, capturedVarName, capturedConfig);
|
|
83
83
|
}).catch(() => { });
|
|
84
84
|
}
|
package/resolveIdRef.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* resolveIdRef.ts — Cached element resolution via #[x] syntax.
|
|
3
3
|
*
|
|
4
|
-
* Dynamically imported by assignFrom when `
|
|
4
|
+
* Dynamically imported by assignFrom when `pin` is provided or `#[x]` patterns are detected.
|
|
5
5
|
* Provides lazy, WeakRef-cached element lookups keyed by variable name.
|
|
6
6
|
*
|
|
7
7
|
* First access: runs the query against the target, auto-assigns an ID if needed, caches via WeakRef.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Configuration for a
|
|
12
|
+
* Configuration for a pin entry.
|
|
13
13
|
*/
|
|
14
14
|
export type WithIdConfig = string | { qry: string } | number[] | { path: number[]; expect?: string; fallback?: boolean };
|
|
15
15
|
|
|
@@ -46,15 +46,15 @@ function generateUniqueId(rootNode: any): string {
|
|
|
46
46
|
*
|
|
47
47
|
* @param varName - The variable name (e.g., 'x' from '#[x]')
|
|
48
48
|
* @param target - The target element to query against
|
|
49
|
-
* @param
|
|
49
|
+
* @param pin - The pin configuration map
|
|
50
50
|
* @returns The resolved element, or undefined if not found
|
|
51
51
|
*/
|
|
52
52
|
export function resolveIdVariable(
|
|
53
53
|
varName: string,
|
|
54
54
|
target: any,
|
|
55
|
-
|
|
55
|
+
pin: Record<string, WithIdConfig>
|
|
56
56
|
): Element | undefined {
|
|
57
|
-
const config =
|
|
57
|
+
const config = pin[varName];
|
|
58
58
|
if (config === undefined) return undefined;
|
|
59
59
|
|
|
60
60
|
// For 'at' option path-based configs (array or { path }), resolve directly from target — no ID, no caching
|
|
@@ -69,10 +69,10 @@ export function resolveIdVariable(
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
if (typeof config === 'object' && 'path' in config && !('qry' in config)) {
|
|
72
|
-
// Determine if this is from 'at' (no ID assignment) or '
|
|
73
|
-
// When called from 'at', we skip ID/caching. When from '
|
|
72
|
+
// Determine if this is from 'at' (no ID assignment) or 'pin' with path (assigns ID + caches)
|
|
73
|
+
// When called from 'at', we skip ID/caching. When from 'pin', we assign ID and cache.
|
|
74
74
|
// Distinguish by presence in the options — caller passes the merged map.
|
|
75
|
-
// For now: { path } without 'noId' → assign ID + cache (
|
|
75
|
+
// For now: { path } without 'noId' → assign ID + cache (pin behavior)
|
|
76
76
|
const rootNode = target.getRootNode?.() ?? target;
|
|
77
77
|
let current: any = target;
|
|
78
78
|
for (const idx of config.path) {
|
|
@@ -91,7 +91,7 @@ export function resolveIdVariable(
|
|
|
91
91
|
// Fire-and-forget: log correction suggestion
|
|
92
92
|
const capturedConfig = config;
|
|
93
93
|
const capturedVarName = varName;
|
|
94
|
-
import('./
|
|
94
|
+
import('./pinCorrector.js').then(module => {
|
|
95
95
|
module.logConfigCorrection(target, capturedVarName, capturedConfig);
|
|
96
96
|
}).catch(() => {});
|
|
97
97
|
}
|