assign-gingerly 0.0.65 → 0.0.66
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 +26 -8
- 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/inferencer/types/assign-gingerly/types.d.ts +58 -0
- package/package.json +4 -4
- package/types/assign-gingerly/types.d.ts +39 -23
- package/builtInEmoji.js +0 -26
package/README.md
CHANGED
|
@@ -816,7 +816,7 @@ While we are in the business of passing values of object A into object B, we mig
|
|
|
816
816
|
|
|
817
817
|
| Operator | Name | Description | Example |
|
|
818
818
|
|----------|------|-------------|---------|
|
|
819
|
-
| ` +=` | Increment | Add to numeric
|
|
819
|
+
| ` +=` | Increment | Add to numeric, concat strings, append to arrays, or [bind events](docs/event-binding.md) | `'count +=': 5` |
|
|
820
820
|
| ` =!` | Toggle | Negate a boolean (or any value via `!`) | `'visible =!': '.'` |
|
|
821
821
|
| ` -=` | Delete | Remove properties from an object | `'?.data -=': 'key'` |
|
|
822
822
|
| ` Y=` | Merge | Recursively `assignGingerly` into a sub-object | `'style Y=': { width: '100px' }` |
|
|
@@ -857,6 +857,8 @@ The `+=` command syntax is `<path> +=` where the path uses the `?.` nested notat
|
|
|
857
857
|
| LHS type | RHS type | Result |
|
|
858
858
|
|----------|----------|--------|
|
|
859
859
|
| number | number | addition (`2 += 3` → `5`) |
|
|
860
|
+
| number | string (numeric) | parse + addition (`5 += '3'` → `8`) |
|
|
861
|
+
| number | string (non-numeric) | string concatenation (`5 += 'px'` → `'5px'`) |
|
|
860
862
|
| string | any | string concatenation (`"hello" += 3` → `"hello3"`) |
|
|
861
863
|
| array | array | array concatenation (`[1,2] += [3,4]` → `[1,2,3,4]`) |
|
|
862
864
|
| array | non-array | push single item (`[1,2] += 3` → `[1,2,3]`) |
|
|
@@ -876,6 +878,22 @@ assignGingerly(obj, {
|
|
|
876
878
|
assignGingerly(obj, { '?.tags +=': 'e' }); // ['a', 'b', 'c', 'd', 'e']
|
|
877
879
|
```
|
|
878
880
|
|
|
881
|
+
**Event binding with `+=`:**
|
|
882
|
+
|
|
883
|
+
When the LHS resolves to a DOM Element and the RHS is an object with an `on` property, `+=` attaches a declarative event listener:
|
|
884
|
+
|
|
885
|
+
```JavaScript
|
|
886
|
+
assignFrom(this.shadowRoot, {
|
|
887
|
+
'?.querySelector?.button +=': {
|
|
888
|
+
on: 'click',
|
|
889
|
+
'?.isHappy =!': '.', // toggle host property
|
|
890
|
+
fromLHS: { '?.age +=': '?.dataset.diff' } // read from button, assign to host
|
|
891
|
+
}
|
|
892
|
+
}, { from: this, withMethods: ['querySelector'] });
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
The handler is lazy-loaded on demand. For full details including assignment vectors, dedup, nudge, and custom event dispatch, see [docs/event-binding.md](docs/event-binding.md).
|
|
896
|
+
|
|
879
897
|
## Example 5 - Toggling boolean values and negating
|
|
880
898
|
|
|
881
899
|
The `=!` command allows us to toggle boolean values:
|
|
@@ -3900,7 +3918,7 @@ await assignFromAsync(container, {
|
|
|
3900
3918
|
if: '?.showPanel',
|
|
3901
3919
|
instantiate: 'globalThis://panelTemplate',
|
|
3902
3920
|
assign: {
|
|
3903
|
-
|
|
3921
|
+
toClone: {
|
|
3904
3922
|
'#[title]?.textContent': '?.panelTitle',
|
|
3905
3923
|
'#[body]?.textContent': '?.panelContent'
|
|
3906
3924
|
},
|
|
@@ -3913,7 +3931,7 @@ await assignFromAsync(container, {
|
|
|
3913
3931
|
}, { from: vm, withMethods: ['querySelector'], protocols: { globalThis: k => globalThis[k] } });
|
|
3914
3932
|
```
|
|
3915
3933
|
|
|
3916
|
-
The `assign.
|
|
3934
|
+
The `assign.toClone` paths resolve against `options.from` (the same source that drives the `if` condition). For multi-element templates, use `assign.configs` (same zip semantics as `manageTemplateList`).
|
|
3917
3935
|
|
|
3918
3936
|
### View Transitions
|
|
3919
3937
|
|
|
@@ -4230,7 +4248,7 @@ assignFrom(document.body, {
|
|
|
4230
4248
|
instantiate: 'globalThis://country-ranking',
|
|
4231
4249
|
},
|
|
4232
4250
|
fromEachItem: {
|
|
4233
|
-
|
|
4251
|
+
toClone: { '?.querySelector?.tr?.ish': '?.' },
|
|
4234
4252
|
withOptions: { withMethods: ['querySelector'], infer: true },
|
|
4235
4253
|
get: { key: '?.rank' }
|
|
4236
4254
|
}
|
|
@@ -4246,7 +4264,7 @@ assignFrom(document.body, {
|
|
|
4246
4264
|
|
|
4247
4265
|
1. Resolves `forEach` (iterable) and `instantiate` (template) from the `resolve` block
|
|
4248
4266
|
2. Clones the template once per item, buffering all clones into a `DocumentFragment`
|
|
4249
|
-
3. For each clone, calls `assignFrom(clone,
|
|
4267
|
+
3. For each clone, calls `assignFrom(clone, toClone, { from: item, ...withOptions })` — distributing the item's data
|
|
4250
4268
|
4. Inserts the fragment between comment markers in one DOM operation
|
|
4251
4269
|
5. On subsequent calls, reconciles by `key` — adds new items, removes missing ones, updates existing clones in place
|
|
4252
4270
|
|
|
@@ -4259,13 +4277,13 @@ The `key` field (in `fromEachItem.get`) identifies each item for stable identity
|
|
|
4259
4277
|
|
|
4260
4278
|
Without `key`, positional matching is used (item[i] → clone[i]).
|
|
4261
4279
|
|
|
4262
|
-
**Shared parent data (`
|
|
4280
|
+
**Shared parent data (`fromHost`):**
|
|
4263
4281
|
|
|
4264
4282
|
Pass data from the outer VM into each clone (e.g., aggregate totals):
|
|
4265
4283
|
|
|
4266
4284
|
```JavaScript
|
|
4267
|
-
|
|
4268
|
-
|
|
4285
|
+
fromHost: {
|
|
4286
|
+
toClone: {
|
|
4269
4287
|
'?.querySelector?.[part~="totalMedalCount"]?.textContent': '?.totalMedalCount'
|
|
4270
4288
|
},
|
|
4271
4289
|
withOptions: { withMethods: ['querySelector'] }
|
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