assign-gingerly 0.0.65 → 0.0.67
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/IterableMixin.js +49 -0
- package/DX/IterableMixin.ts +62 -0
- package/{installForwarding.js → DX/installForwarding.js} +2 -2
- package/{installForwarding.ts → DX/installForwarding.ts} +2 -2
- package/DX/paths.js +381 -0
- package/{paths.ts → DX/paths.ts} +1 -1
- package/README.md +43 -13
- package/assignFrom.js +3 -3
- package/assignFrom.ts +6 -5
- package/assignFromAsync.js +3 -3
- package/assignFromAsync.ts +5 -5
- package/assignGingerly.js +52 -10
- package/assignGingerly.ts +53 -10
- package/assignTentatively.js +8 -0
- package/assignTentatively.ts +6 -0
- package/{builtInEmoji.ts → emojis.js} +46 -34
- package/emojis.ts +52 -0
- package/getValues.js +0 -1
- package/getValues.ts +1 -1
- package/handlers/addEventListener.js +153 -0
- package/handlers/addEventListener.ts +178 -0
- package/handlers/lazyLoad.js +3 -3
- package/handlers/lazyLoad.ts +3 -3
- package/handlers/manageTemplateList.js +47 -20
- package/handlers/manageTemplateList.ts +50 -20
- package/index.js +1 -1
- package/index.ts +1 -1
- package/inferencer/types/assign-gingerly/types.d.ts +62 -4
- package/package.json +12 -7
- package/resolveIdRef.js +1 -1
- package/resolveIdRef.ts +1 -1
- package/types/assign-gingerly/types.d.ts +39 -23
- package/builtInEmoji.js +0 -26
- package/paths.js +0 -231
- /package/{pinCorrector.js → DX/pinCorrector.js} +0 -0
- /package/{pinCorrector.ts → DX/pinCorrector.ts} +0 -0
package/assignFrom.js
CHANGED
|
@@ -307,7 +307,7 @@ function processIdRefNormalKeys(idRefNormalKeys, expandedPattern, target, option
|
|
|
307
307
|
const ids = getEffectiveIds(options);
|
|
308
308
|
if (!ids)
|
|
309
309
|
return;
|
|
310
|
-
|
|
310
|
+
const { withMethods, aka, akaMethods, protocols, from } = options;
|
|
311
311
|
for (const key of idRefNormalKeys) {
|
|
312
312
|
const parsed = parseIdRef(key);
|
|
313
313
|
if (!parsed)
|
|
@@ -317,11 +317,11 @@ function processIdRefNormalKeys(idRefNormalKeys, expandedPattern, target, option
|
|
|
317
317
|
continue;
|
|
318
318
|
const value = expandedPattern[key];
|
|
319
319
|
if (parsed.remainingPath) {
|
|
320
|
-
const resolvedValue = getValues({ __v: value },
|
|
320
|
+
const resolvedValue = getValues({ __v: value }, from, { withMethods, aka, akaMethods, protocols, root: target });
|
|
321
321
|
assignGingerly(el, { [parsed.remainingPath]: resolvedValue.__v }, options);
|
|
322
322
|
}
|
|
323
323
|
else {
|
|
324
|
-
const resolvedValue = getValues(typeof value === 'object' && value !== null ? value : { __v: value },
|
|
324
|
+
const resolvedValue = getValues(typeof value === 'object' && value !== null ? value : { __v: value }, from, { withMethods, aka, akaMethods, protocols, root: target });
|
|
325
325
|
if (!('__v' in resolvedValue)) {
|
|
326
326
|
assignGingerly(el, resolvedValue, options);
|
|
327
327
|
}
|
package/assignFrom.ts
CHANGED
|
@@ -321,7 +321,8 @@ function processIdRefNormalKeys(
|
|
|
321
321
|
): void {
|
|
322
322
|
const ids = getEffectiveIds(options);
|
|
323
323
|
if (!ids) return;
|
|
324
|
-
|
|
324
|
+
|
|
325
|
+
const { withMethods, aka, akaMethods, protocols, from } = options;
|
|
325
326
|
for (const key of idRefNormalKeys) {
|
|
326
327
|
const parsed = parseIdRef(key);
|
|
327
328
|
if (!parsed) continue;
|
|
@@ -332,15 +333,15 @@ function processIdRefNormalKeys(
|
|
|
332
333
|
const value = expandedPattern[key];
|
|
333
334
|
if (parsed.remainingPath) {
|
|
334
335
|
const resolvedValue = getValues(
|
|
335
|
-
{ __v: value },
|
|
336
|
-
{ withMethods
|
|
336
|
+
{ __v: value }, from,
|
|
337
|
+
{ withMethods, aka, akaMethods, protocols, root: target }
|
|
337
338
|
);
|
|
338
339
|
assignGingerly(el, { [parsed.remainingPath]: resolvedValue.__v }, options);
|
|
339
340
|
} else {
|
|
340
341
|
const resolvedValue = getValues(
|
|
341
342
|
typeof value === 'object' && value !== null ? value : { __v: value },
|
|
342
|
-
|
|
343
|
-
{ withMethods
|
|
343
|
+
from,
|
|
344
|
+
{ withMethods, aka, akaMethods, protocols, root: target }
|
|
344
345
|
);
|
|
345
346
|
if (!('__v' in resolvedValue)) {
|
|
346
347
|
assignGingerly(el, resolvedValue, options);
|
package/assignFromAsync.js
CHANGED
|
@@ -46,7 +46,7 @@ export async function assignFromAsync(target, pattern, options, permissions) {
|
|
|
46
46
|
if (idRefNormalKeys.length > 0 && (options.pin || options.at)) {
|
|
47
47
|
const ids = { ...options.pin, ...options.at };
|
|
48
48
|
const { resolveIdVariable, parseIdRef } = await import('./resolveIdRef.js');
|
|
49
|
-
|
|
49
|
+
const { withMethods, aka, akaMethods, protocols, from } = options;
|
|
50
50
|
for (const key of idRefNormalKeys) {
|
|
51
51
|
const parsed = parseIdRef(key);
|
|
52
52
|
if (!parsed)
|
|
@@ -57,13 +57,13 @@ export async function assignFromAsync(target, pattern, options, permissions) {
|
|
|
57
57
|
const value = expandedPattern[key];
|
|
58
58
|
if (parsed.remainingPath) {
|
|
59
59
|
// Resolve the RHS value
|
|
60
|
-
const resolvedValue = await resolveValues({ __v: value },
|
|
60
|
+
const resolvedValue = await resolveValues({ __v: value }, from, { withMethods, aka, akaMethods, protocols, root: el });
|
|
61
61
|
// Apply remaining path on the resolved element
|
|
62
62
|
assignGingerly(el, { [parsed.remainingPath]: resolvedValue.__v }, options);
|
|
63
63
|
}
|
|
64
64
|
else {
|
|
65
65
|
// No remaining path — resolve and assign directly to the element
|
|
66
|
-
const resolvedValue = await resolveValues(typeof value === 'object' && value !== null ? value : { __v: value },
|
|
66
|
+
const resolvedValue = await resolveValues(typeof value === 'object' && value !== null ? value : { __v: value }, from, { withMethods, aka, akaMethods, protocols, root: el });
|
|
67
67
|
if ('__v' in resolvedValue) {
|
|
68
68
|
// Single value — can't assign to element root without a path
|
|
69
69
|
}
|
package/assignFromAsync.ts
CHANGED
|
@@ -83,7 +83,7 @@ export async function assignFromAsync(
|
|
|
83
83
|
if (idRefNormalKeys.length > 0 && (options.pin || options.at)) {
|
|
84
84
|
const ids = { ...options.pin, ...options.at };
|
|
85
85
|
const { resolveIdVariable, parseIdRef } = await import('./resolveIdRef.js');
|
|
86
|
-
|
|
86
|
+
const { withMethods, aka, akaMethods, protocols, from } = options;
|
|
87
87
|
for (const key of idRefNormalKeys) {
|
|
88
88
|
const parsed = parseIdRef(key);
|
|
89
89
|
if (!parsed) continue;
|
|
@@ -95,8 +95,8 @@ export async function assignFromAsync(
|
|
|
95
95
|
if (parsed.remainingPath) {
|
|
96
96
|
// Resolve the RHS value
|
|
97
97
|
const resolvedValue = await resolveValues(
|
|
98
|
-
{ __v: value },
|
|
99
|
-
{ withMethods
|
|
98
|
+
{ __v: value }, from,
|
|
99
|
+
{ withMethods, aka, akaMethods, protocols, root: el }
|
|
100
100
|
);
|
|
101
101
|
// Apply remaining path on the resolved element
|
|
102
102
|
assignGingerly(el, { [parsed.remainingPath]: resolvedValue.__v }, options);
|
|
@@ -104,8 +104,8 @@ export async function assignFromAsync(
|
|
|
104
104
|
// No remaining path — resolve and assign directly to the element
|
|
105
105
|
const resolvedValue = await resolveValues(
|
|
106
106
|
typeof value === 'object' && value !== null ? value : { __v: value },
|
|
107
|
-
|
|
108
|
-
{ withMethods
|
|
107
|
+
from,
|
|
108
|
+
{ withMethods, aka, akaMethods, protocols, root: el }
|
|
109
109
|
);
|
|
110
110
|
if ('__v' in resolvedValue) {
|
|
111
111
|
// Single value — can't assign to element root without a path
|
package/assignGingerly.js
CHANGED
|
@@ -562,7 +562,6 @@ export function assignGingerly(target, source, options, permissions) {
|
|
|
562
562
|
if (!target || typeof target !== 'object') {
|
|
563
563
|
return target;
|
|
564
564
|
}
|
|
565
|
-
//TODO
|
|
566
565
|
const { aliasMap, withMethods: withMethodsSet } = normalizeAliasOptions(options);
|
|
567
566
|
// Convert withAsyncMethods array to Set for O(1) lookup
|
|
568
567
|
const withAsyncMethodsSet = options?.withAsyncMethods
|
|
@@ -639,22 +638,61 @@ export function assignGingerly(target, source, options, permissions) {
|
|
|
639
638
|
if (path) {
|
|
640
639
|
if (isNestedPath(path)) {
|
|
641
640
|
const pathParts = parsePath(path);
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
641
|
+
// Check for withMethods path evaluation
|
|
642
|
+
let lhsValue;
|
|
643
|
+
let lhsParent;
|
|
644
|
+
let lhsKey;
|
|
645
|
+
if (withMethodsSet) {
|
|
646
|
+
const result = evaluatePathWithMethods(target, pathParts, value, withMethodsSet);
|
|
647
|
+
lhsParent = result.target;
|
|
648
|
+
lhsKey = result.lastKey;
|
|
649
|
+
lhsValue = lhsParent[lhsKey];
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
lhsKey = pathParts[pathParts.length - 1];
|
|
653
|
+
lhsParent = ensureNestedPath(target, pathParts);
|
|
654
|
+
lhsValue = lhsParent[lhsKey];
|
|
655
|
+
}
|
|
656
|
+
// Event handler: Element LHS + object RHS with 'on' property
|
|
657
|
+
if (lhsValue instanceof Element && value && typeof value === 'object' && !Array.isArray(value) && 'on' in value) {
|
|
658
|
+
const capturedLhs = lhsValue;
|
|
659
|
+
const capturedValue = value;
|
|
660
|
+
const capturedTarget = target;
|
|
661
|
+
const capturedOptions = options;
|
|
662
|
+
import('./handlers/addEventListener.js').then(({ attachEventListener }) => {
|
|
663
|
+
attachEventListener(capturedLhs, capturedValue, capturedTarget, capturedOptions?.from ?? capturedTarget, capturedOptions ?? {});
|
|
664
|
+
});
|
|
665
|
+
continue;
|
|
646
666
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
667
|
+
if (!(lhsKey in lhsParent)) {
|
|
668
|
+
lhsParent[lhsKey] = value;
|
|
669
|
+
}
|
|
670
|
+
else if (Array.isArray(lhsValue)) {
|
|
671
|
+
lhsParent[lhsKey] = Array.isArray(value)
|
|
672
|
+
? [...lhsValue, ...value]
|
|
673
|
+
: [...lhsValue, value];
|
|
674
|
+
}
|
|
675
|
+
else if (typeof lhsValue === 'number' && typeof value === 'string') {
|
|
676
|
+
const parsed = Number(value);
|
|
677
|
+
lhsParent[lhsKey] = isNaN(parsed) ? lhsValue + value : lhsValue + parsed;
|
|
651
678
|
}
|
|
652
679
|
else {
|
|
653
|
-
|
|
680
|
+
lhsParent[lhsKey] += value;
|
|
654
681
|
}
|
|
655
682
|
}
|
|
656
683
|
else {
|
|
657
684
|
// Plain key - direct operation on target
|
|
685
|
+
// Event handler: Element LHS + object RHS with 'on' property
|
|
686
|
+
if (target[path] instanceof Element && value && typeof value === 'object' && !Array.isArray(value) && 'on' in value) {
|
|
687
|
+
const capturedLhs = target[path];
|
|
688
|
+
const capturedValue = value;
|
|
689
|
+
const capturedTarget = target;
|
|
690
|
+
const capturedOptions = options;
|
|
691
|
+
import('./handlers/addEventListener.js').then(({ attachEventListener }) => {
|
|
692
|
+
attachEventListener(capturedLhs, capturedValue, capturedTarget, capturedOptions?.from ?? capturedTarget, capturedOptions ?? {});
|
|
693
|
+
});
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
658
696
|
if (!(path in target)) {
|
|
659
697
|
target[path] = value;
|
|
660
698
|
}
|
|
@@ -663,6 +701,10 @@ export function assignGingerly(target, source, options, permissions) {
|
|
|
663
701
|
? [...target[path], ...value]
|
|
664
702
|
: [...target[path], value];
|
|
665
703
|
}
|
|
704
|
+
else if (typeof target[path] === 'number' && typeof value === 'string') {
|
|
705
|
+
const parsed = Number(value);
|
|
706
|
+
target[path] = isNaN(parsed) ? target[path] + value : target[path] + parsed;
|
|
707
|
+
}
|
|
666
708
|
else {
|
|
667
709
|
target[path] += value;
|
|
668
710
|
}
|
package/assignGingerly.ts
CHANGED
|
@@ -767,7 +767,6 @@ export function assignGingerly(
|
|
|
767
767
|
if (!target || typeof target !== 'object') {
|
|
768
768
|
return target;
|
|
769
769
|
}
|
|
770
|
-
//TODO
|
|
771
770
|
|
|
772
771
|
const { aliasMap, withMethods: withMethodsSet } = normalizeAliasOptions(options);
|
|
773
772
|
|
|
@@ -852,25 +851,69 @@ export function assignGingerly(
|
|
|
852
851
|
if (path) {
|
|
853
852
|
if (isNestedPath(path)) {
|
|
854
853
|
const pathParts = parsePath(path);
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
854
|
+
|
|
855
|
+
// Check for withMethods path evaluation
|
|
856
|
+
let lhsValue: any;
|
|
857
|
+
let lhsParent: any;
|
|
858
|
+
let lhsKey: string;
|
|
859
|
+
if (withMethodsSet) {
|
|
860
|
+
const result = evaluatePathWithMethods(target, pathParts, value, withMethodsSet);
|
|
861
|
+
lhsParent = result.target;
|
|
862
|
+
lhsKey = result.lastKey;
|
|
863
|
+
lhsValue = lhsParent[lhsKey];
|
|
864
|
+
} else {
|
|
865
|
+
lhsKey = pathParts[pathParts.length - 1];
|
|
866
|
+
lhsParent = ensureNestedPath(target, pathParts);
|
|
867
|
+
lhsValue = lhsParent[lhsKey];
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// Event handler: Element LHS + object RHS with 'on' property
|
|
871
|
+
if (lhsValue instanceof Element && value && typeof value === 'object' && !Array.isArray(value) && 'on' in value) {
|
|
872
|
+
const capturedLhs = lhsValue;
|
|
873
|
+
const capturedValue = value;
|
|
874
|
+
const capturedTarget = target;
|
|
875
|
+
const capturedOptions = options;
|
|
876
|
+
import('./handlers/addEventListener.js').then(({ attachEventListener }) => {
|
|
877
|
+
attachEventListener(capturedLhs, capturedValue, capturedTarget, capturedOptions?.from ?? capturedTarget, capturedOptions ?? {});
|
|
878
|
+
});
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
if (!(lhsKey in lhsParent)) {
|
|
883
|
+
lhsParent[lhsKey] = value;
|
|
884
|
+
} else if (Array.isArray(lhsValue)) {
|
|
885
|
+
lhsParent[lhsKey] = Array.isArray(value)
|
|
886
|
+
? [...lhsValue, ...value]
|
|
887
|
+
: [...lhsValue, value];
|
|
888
|
+
} else if (typeof lhsValue === 'number' && typeof value === 'string') {
|
|
889
|
+
const parsed = Number(value);
|
|
890
|
+
lhsParent[lhsKey] = isNaN(parsed) ? lhsValue + value : lhsValue + parsed;
|
|
863
891
|
} else {
|
|
864
|
-
|
|
892
|
+
lhsParent[lhsKey] += value;
|
|
865
893
|
}
|
|
866
894
|
} else {
|
|
867
895
|
// Plain key - direct operation on target
|
|
896
|
+
// Event handler: Element LHS + object RHS with 'on' property
|
|
897
|
+
if (target[path] instanceof Element && value && typeof value === 'object' && !Array.isArray(value) && 'on' in value) {
|
|
898
|
+
const capturedLhs = target[path];
|
|
899
|
+
const capturedValue = value;
|
|
900
|
+
const capturedTarget = target;
|
|
901
|
+
const capturedOptions = options;
|
|
902
|
+
import('./handlers/addEventListener.js').then(({ attachEventListener }) => {
|
|
903
|
+
attachEventListener(capturedLhs, capturedValue, capturedTarget, capturedOptions?.from ?? capturedTarget, capturedOptions ?? {});
|
|
904
|
+
});
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
|
|
868
908
|
if (!(path in target)) {
|
|
869
909
|
target[path] = value;
|
|
870
910
|
} else if (Array.isArray(target[path])) {
|
|
871
911
|
target[path] = Array.isArray(value)
|
|
872
912
|
? [...target[path], ...value]
|
|
873
913
|
: [...target[path], value];
|
|
914
|
+
} else if (typeof target[path] === 'number' && typeof value === 'string') {
|
|
915
|
+
const parsed = Number(value);
|
|
916
|
+
target[path] = isNaN(parsed) ? target[path] + value : target[path] + parsed;
|
|
874
917
|
} else {
|
|
875
918
|
target[path] += value;
|
|
876
919
|
}
|
package/assignTentatively.js
CHANGED
|
@@ -129,6 +129,10 @@ export function assignTentatively(target, source, options) {
|
|
|
129
129
|
? [...parent[lastKey], ...value]
|
|
130
130
|
: [...parent[lastKey], value];
|
|
131
131
|
}
|
|
132
|
+
else if (typeof parent[lastKey] === 'number' && typeof value === 'string') {
|
|
133
|
+
const parsed = Number(value);
|
|
134
|
+
parent[lastKey] = isNaN(parsed) ? parent[lastKey] + value : parent[lastKey] + parsed;
|
|
135
|
+
}
|
|
132
136
|
else {
|
|
133
137
|
parent[lastKey] += value;
|
|
134
138
|
}
|
|
@@ -149,6 +153,10 @@ export function assignTentatively(target, source, options) {
|
|
|
149
153
|
? [...target[path], ...value]
|
|
150
154
|
: [...target[path], value];
|
|
151
155
|
}
|
|
156
|
+
else if (typeof target[path] === 'number' && typeof value === 'string') {
|
|
157
|
+
const parsed = Number(value);
|
|
158
|
+
target[path] = isNaN(parsed) ? target[path] + value : target[path] + parsed;
|
|
159
|
+
}
|
|
152
160
|
else {
|
|
153
161
|
target[path] += value;
|
|
154
162
|
}
|
package/assignTentatively.ts
CHANGED
|
@@ -155,6 +155,9 @@ export function assignTentatively(
|
|
|
155
155
|
parent[lastKey] = Array.isArray(value)
|
|
156
156
|
? [...parent[lastKey], ...value]
|
|
157
157
|
: [...parent[lastKey], value];
|
|
158
|
+
} else if (typeof parent[lastKey] === 'number' && typeof value === 'string') {
|
|
159
|
+
const parsed = Number(value);
|
|
160
|
+
parent[lastKey] = isNaN(parsed) ? parent[lastKey] + value : parent[lastKey] + parsed;
|
|
158
161
|
} else {
|
|
159
162
|
parent[lastKey] += value;
|
|
160
163
|
}
|
|
@@ -172,6 +175,9 @@ export function assignTentatively(
|
|
|
172
175
|
target[path] = Array.isArray(value)
|
|
173
176
|
? [...target[path], ...value]
|
|
174
177
|
: [...target[path], value];
|
|
178
|
+
} else if (typeof target[path] === 'number' && typeof value === 'string') {
|
|
179
|
+
const parsed = Number(value);
|
|
180
|
+
target[path] = isNaN(parsed) ? target[path] + value : target[path] + parsed;
|
|
175
181
|
} else {
|
|
176
182
|
target[path] += value;
|
|
177
183
|
}
|
|
@@ -1,34 +1,46 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* builtInEmoji.ts — Predefined emoji aliases for built-in handlers.
|
|
3
|
-
*
|
|
4
|
-
* Import and spread into the `handlers` option for concise handler configs:
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* import { builtInEmoji } from 'assign-gingerly/builtInEmoji.js';
|
|
8
|
-
*
|
|
9
|
-
* assignFrom(target, {
|
|
10
|
-
* '?.el =>': { do: '🔗', get: { value: ['?.first', ' ', '?.last'] } }
|
|
11
|
-
* }, { from: vm, handlers: builtInEmoji });
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* |
|
|
20
|
-
* |
|
|
21
|
-
* |
|
|
22
|
-
* |
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
/**
|
|
2
|
+
* builtInEmoji.ts — Predefined emoji aliases for built-in handlers.
|
|
3
|
+
*
|
|
4
|
+
* Import and spread into the `handlers` option for concise handler configs:
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* import { builtInEmoji } from 'assign-gingerly/builtInEmoji.js';
|
|
8
|
+
*
|
|
9
|
+
* assignFrom(target, {
|
|
10
|
+
* '?.el =>': { do: '🔗', get: { value: ['?.first', ' ', '?.last'] } }
|
|
11
|
+
* }, { from: vm, handlers: builtInEmoji });
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Emoji → built-in handler name mapping.
|
|
15
|
+
*
|
|
16
|
+
* | Emoji | Handler |
|
|
17
|
+
* |-------|---------|
|
|
18
|
+
* | 📦 | builtIns.lazyLoad |
|
|
19
|
+
* | 🎚️ | builtIns.lazyLoadSwitch |
|
|
20
|
+
* | 🔗 | builtIns.join |
|
|
21
|
+
* | 🏷️ | builtIns.microDataJoin |
|
|
22
|
+
* | 📋 | builtIns.manageTemplateList |
|
|
23
|
+
*/
|
|
24
|
+
export const builtInEmoji = {
|
|
25
|
+
'📦': 'builtIns.lazyLoad',
|
|
26
|
+
'🎚️': 'builtIns.lazyLoadSwitch',
|
|
27
|
+
'🔗': 'builtIns.join',
|
|
28
|
+
'🏷️': 'builtIns.microDataJoin',
|
|
29
|
+
'📋': 'builtIns.manageTemplateList',
|
|
30
|
+
'📊': 'builtIns.rangeSelector',
|
|
31
|
+
};
|
|
32
|
+
export const akaMethods = {
|
|
33
|
+
'🔍': 'querySelector',
|
|
34
|
+
'🧺': 'querySelectorAll',
|
|
35
|
+
'+': 'add',
|
|
36
|
+
'🧬': 'cloneNode'
|
|
37
|
+
};
|
|
38
|
+
export const aka = {
|
|
39
|
+
'©️': 'content?.cloneNode?.true',
|
|
40
|
+
//'🔎': 'clone?.querySelector'
|
|
41
|
+
};
|
|
42
|
+
export const emojis = {
|
|
43
|
+
builtInEmoji,
|
|
44
|
+
akaMethods,
|
|
45
|
+
};
|
|
46
|
+
export default emojis;
|
package/emojis.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* builtInEmoji.ts — Predefined emoji aliases for built-in handlers.
|
|
3
|
+
*
|
|
4
|
+
* Import and spread into the `handlers` option for concise handler configs:
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* import { builtInEmoji } from 'assign-gingerly/builtInEmoji.js';
|
|
8
|
+
*
|
|
9
|
+
* assignFrom(target, {
|
|
10
|
+
* '?.el =>': { do: '🔗', get: { value: ['?.first', ' ', '?.last'] } }
|
|
11
|
+
* }, { from: vm, handlers: builtInEmoji });
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Emoji → built-in handler name mapping.
|
|
16
|
+
*
|
|
17
|
+
* | Emoji | Handler |
|
|
18
|
+
* |-------|---------|
|
|
19
|
+
* | 📦 | builtIns.lazyLoad |
|
|
20
|
+
* | 🎚️ | builtIns.lazyLoadSwitch |
|
|
21
|
+
* | 🔗 | builtIns.join |
|
|
22
|
+
* | 🏷️ | builtIns.microDataJoin |
|
|
23
|
+
* | 📋 | builtIns.manageTemplateList |
|
|
24
|
+
*/
|
|
25
|
+
export const builtInEmoji: Record<string, string> = {
|
|
26
|
+
'📦': 'builtIns.lazyLoad',
|
|
27
|
+
'🎚️': 'builtIns.lazyLoadSwitch',
|
|
28
|
+
'🔗': 'builtIns.join',
|
|
29
|
+
'🏷️': 'builtIns.microDataJoin',
|
|
30
|
+
'📋': 'builtIns.manageTemplateList',
|
|
31
|
+
'📊': 'builtIns.rangeSelector',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const akaMethods: Record<string, string> = {
|
|
35
|
+
'🔍': 'querySelector',
|
|
36
|
+
'🧺': 'querySelectorAll',
|
|
37
|
+
'+': 'add',
|
|
38
|
+
'🧬': 'cloneNode'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const aka: Record<string, string> = {
|
|
42
|
+
'©️': 'content?.cloneNode?.true',
|
|
43
|
+
//'🔎': 'clone?.querySelector'
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
export const emojis = {
|
|
48
|
+
builtInEmoji,
|
|
49
|
+
akaMethods,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default emojis;
|
package/getValues.js
CHANGED
package/getValues.ts
CHANGED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* handlers/addEventListener.ts — Event binding handler for += operator.
|
|
3
|
+
*
|
|
4
|
+
* Dynamically imported when assignGingerly/assignFrom detects an += with
|
|
5
|
+
* an object RHS containing an `on` property on a DOM Element LHS.
|
|
6
|
+
*
|
|
7
|
+
* Attaches an event listener that executes assign vectors on event fire.
|
|
8
|
+
*/
|
|
9
|
+
import assignGingerly from '../assignGingerly.js';
|
|
10
|
+
/**
|
|
11
|
+
* WeakMap for dedup: Element → Map<key, AbortController>
|
|
12
|
+
*/
|
|
13
|
+
const keyMap = new WeakMap();
|
|
14
|
+
/**
|
|
15
|
+
* Reserved keys that are not shorthand assign patterns.
|
|
16
|
+
*/
|
|
17
|
+
const RESERVED_KEYS = new Set([
|
|
18
|
+
'on', 'get', 'fromLHS', 'fromHost', 'fromEvent', 'fromTarget',
|
|
19
|
+
'toTarget', 'toHost', 'toLHS', 'withOptions', 'toTargetOptions',
|
|
20
|
+
'toHostOptions', 'toLHSOptions', 'dispatch', 'nudge'
|
|
21
|
+
]);
|
|
22
|
+
/**
|
|
23
|
+
* Extract shorthand keys (implicit toHost) from a vector config.
|
|
24
|
+
* Any key not in RESERVED_KEYS that starts with '?.' or contains an operator is shorthand.
|
|
25
|
+
*/
|
|
26
|
+
function extractShorthand(config) {
|
|
27
|
+
const shorthand = {};
|
|
28
|
+
let hasAny = false;
|
|
29
|
+
for (const key of Object.keys(config)) {
|
|
30
|
+
if (!RESERVED_KEYS.has(key)) {
|
|
31
|
+
shorthand[key] = config[key];
|
|
32
|
+
hasAny = true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return hasAny ? shorthand : null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Process a single AssignDispatchVector — execute all toTarget/toHost/toLHS assignments.
|
|
39
|
+
*/
|
|
40
|
+
function processVector(vector, source, target, host, lhs, inheritedOptions, useAssignFrom) {
|
|
41
|
+
const destinations = [
|
|
42
|
+
{ key: 'toTarget', dest: target },
|
|
43
|
+
{ key: 'toHost', dest: host },
|
|
44
|
+
{ key: 'toLHS', dest: lhs },
|
|
45
|
+
];
|
|
46
|
+
for (const { key, dest } of destinations) {
|
|
47
|
+
const pattern = vector[key];
|
|
48
|
+
if (!pattern || Object.keys(pattern).length === 0)
|
|
49
|
+
continue;
|
|
50
|
+
if (useAssignFrom && source != null) {
|
|
51
|
+
// Dynamic import assignFrom on demand (fire-and-forget context, already async)
|
|
52
|
+
import('../assignFrom.js').then(({ assignFrom }) => {
|
|
53
|
+
assignFrom(dest, pattern, { from: source, ...inheritedOptions, ...vector.withOptions });
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
assignGingerly(dest, pattern, inheritedOptions);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Handle shorthand (implicit toHost)
|
|
61
|
+
const shorthand = extractShorthand(vector);
|
|
62
|
+
if (shorthand) {
|
|
63
|
+
if (useAssignFrom && source != null) {
|
|
64
|
+
import('../assignFrom.js').then(({ assignFrom }) => {
|
|
65
|
+
assignFrom(host, shorthand, { from: source, ...inheritedOptions, ...vector.withOptions });
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
assignGingerly(host, shorthand, inheritedOptions);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Attach an event listener based on AddEventListenerConfig.
|
|
75
|
+
*
|
|
76
|
+
* @param lhs - The DOM element to attach the listener to
|
|
77
|
+
* @param config - The event handler configuration
|
|
78
|
+
* @param target - The assignFrom target (first arg)
|
|
79
|
+
* @param host - The options.from (source/view model)
|
|
80
|
+
* @param inheritedOptions - Parent assignFrom options (withMethods, aka, etc.)
|
|
81
|
+
*/
|
|
82
|
+
export function attachEventListener(lhs, config, target, host, inheritedOptions) {
|
|
83
|
+
const { on: eventName, get: getConfig, fromLHS, fromHost, fromTarget, fromEvent, dispatch } = config;
|
|
84
|
+
// Resolve get config values
|
|
85
|
+
const { abortController, key, nudge, options: listenerOptions, stopPropagation, preventDefault, dispatch: getDispatch } = getConfig ?? {};
|
|
86
|
+
// Handle dedup via key
|
|
87
|
+
let controller;
|
|
88
|
+
if (key) {
|
|
89
|
+
let elMap = keyMap.get(lhs);
|
|
90
|
+
if (!elMap) {
|
|
91
|
+
elMap = new Map();
|
|
92
|
+
keyMap.set(lhs, elMap);
|
|
93
|
+
}
|
|
94
|
+
// Abort previous listener with same key
|
|
95
|
+
const prev = elMap.get(key);
|
|
96
|
+
if (prev)
|
|
97
|
+
prev.abort();
|
|
98
|
+
// Create new controller for this key
|
|
99
|
+
controller = new AbortController();
|
|
100
|
+
elMap.set(key, controller);
|
|
101
|
+
}
|
|
102
|
+
else if (abortController instanceof AbortController) {
|
|
103
|
+
controller = abortController;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
controller = new AbortController();
|
|
107
|
+
}
|
|
108
|
+
// Attach the listener
|
|
109
|
+
lhs.addEventListener(eventName, (event) => {
|
|
110
|
+
if (stopPropagation)
|
|
111
|
+
event.stopPropagation();
|
|
112
|
+
if (preventDefault)
|
|
113
|
+
event.preventDefault();
|
|
114
|
+
// Static assignments (no from) — top-level toTarget/toHost/toLHS + shorthand
|
|
115
|
+
processVector(config, null, target, host, lhs, inheritedOptions, false);
|
|
116
|
+
// fromLHS assignments
|
|
117
|
+
if (fromLHS) {
|
|
118
|
+
processVector(fromLHS, lhs, target, host, lhs, inheritedOptions, true);
|
|
119
|
+
}
|
|
120
|
+
// fromHost assignments
|
|
121
|
+
if (fromHost) {
|
|
122
|
+
processVector(fromHost, host, target, host, lhs, inheritedOptions, true);
|
|
123
|
+
}
|
|
124
|
+
// fromTarget assignments
|
|
125
|
+
if (fromTarget) {
|
|
126
|
+
processVector(fromTarget, target, target, host, lhs, inheritedOptions, true);
|
|
127
|
+
}
|
|
128
|
+
// fromEvent assignments
|
|
129
|
+
if (fromEvent) {
|
|
130
|
+
processVector(fromEvent, event, target, host, lhs, inheritedOptions, true);
|
|
131
|
+
}
|
|
132
|
+
// Dispatch custom event if configured
|
|
133
|
+
const dispatchConfig = dispatch || getDispatch;
|
|
134
|
+
if (dispatchConfig && dispatchConfig.type) {
|
|
135
|
+
const EventCtr = (typeof dispatchConfig.eventCtr === 'function'
|
|
136
|
+
? dispatchConfig.eventCtr
|
|
137
|
+
: CustomEvent);
|
|
138
|
+
const evt = new EventCtr(dispatchConfig.type, {
|
|
139
|
+
detail: dispatchConfig.detail,
|
|
140
|
+
bubbles: dispatchConfig.bubbles ?? true,
|
|
141
|
+
cancelable: dispatchConfig.cancelable ?? false,
|
|
142
|
+
composed: dispatchConfig.composed ?? true,
|
|
143
|
+
});
|
|
144
|
+
lhs.dispatchEvent(evt);
|
|
145
|
+
}
|
|
146
|
+
}, { signal: controller.signal, ...listenerOptions });
|
|
147
|
+
// Nudge: remove disabled, add interaction hints
|
|
148
|
+
if (nudge) {
|
|
149
|
+
import('./nudge.js').then(({ nudge: nudgeFn }) => {
|
|
150
|
+
nudgeFn(lhs);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|