assign-gingerly 0.0.85 → 0.0.87
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.js +5 -3
- package/DX/emojis.ts +5 -3
- package/DX/paths.js +6 -2
- package/DX/paths.ts +29 -23
- package/README.md +34 -39
- package/assignFrom.js +78 -2
- package/assignFrom.ts +80 -2
- package/inferencer/types/NewCustomElementFeature.md +3 -1
- package/inferencer/types/NewHTMLFirstCustomElement.md +2 -0
- package/inferencer/types/assign-gingerly/types.d.ts +43 -5
- package/inferencer/types/swipe-dismiss/types.d.ts +7 -4
- package/package.json +9 -4
- package/processHandlerCommands.js +5 -55
- package/processHandlerCommands.ts +6 -51
- package/{handlers → syncOps}/join.js +61 -73
- package/syncOps/join.ts +62 -0
- package/syncOps/registry.js +15 -0
- package/syncOps/registry.ts +19 -0
- package/utils/resolveLhsPath.js +68 -0
- package/utils/resolveLhsPath.ts +81 -0
- package/handlers/join.ts +0 -79
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolveLhsPath.ts — Shared LHS path resolution for operator commands.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the `?.`-prefixed path in front of an operator suffix (` =>`, ` =&`, ...)
|
|
5
|
+
* against a target, preserving the parent object and final key so the caller can
|
|
6
|
+
* assign a computed/returned value back to that path.
|
|
7
|
+
*
|
|
8
|
+
* Shared by processHandlerCommands.ts (` =>`) and the sync-op dispatcher in
|
|
9
|
+
* assignFrom.ts (` =&`) — the two operators that hand a value back to the LHS
|
|
10
|
+
* rather than assigning it directly.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { evaluatePathWithMethods } from '../assignGingerly.js';
|
|
14
|
+
|
|
15
|
+
export interface ResolvedLhsPath {
|
|
16
|
+
lhsTarget: any;
|
|
17
|
+
lhsParent: any;
|
|
18
|
+
lhsKey: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ResolveLhsPathOptions {
|
|
22
|
+
withMethods?: Set<string> | string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function resolveLhsPath(
|
|
26
|
+
target: any,
|
|
27
|
+
lhsPath: string,
|
|
28
|
+
options: ResolveLhsPathOptions
|
|
29
|
+
): ResolvedLhsPath {
|
|
30
|
+
let lhsTarget: any;
|
|
31
|
+
let lhsParent: any = undefined;
|
|
32
|
+
let lhsKey: string | undefined = undefined;
|
|
33
|
+
|
|
34
|
+
if (lhsPath.startsWith('?.')) {
|
|
35
|
+
const pathParts = lhsPath.split('?.').filter(p => p.length > 0);
|
|
36
|
+
const withMethodsSet = options.withMethods
|
|
37
|
+
? options.withMethods instanceof Set
|
|
38
|
+
? options.withMethods
|
|
39
|
+
: new Set(options.withMethods)
|
|
40
|
+
: undefined;
|
|
41
|
+
|
|
42
|
+
if (withMethodsSet && pathParts.length > 0) {
|
|
43
|
+
const result = evaluatePathWithMethods(target, pathParts, undefined, withMethodsSet);
|
|
44
|
+
lhsParent = result.target;
|
|
45
|
+
lhsKey = result.lastKey;
|
|
46
|
+
lhsTarget = result.target[result.lastKey];
|
|
47
|
+
// If last key is a method, call it to get the target
|
|
48
|
+
if (result.isMethod && typeof result.target[result.lastKey] === 'function') {
|
|
49
|
+
lhsTarget = result.target[result.lastKey].call(result.target);
|
|
50
|
+
lhsParent = undefined; // Can't assign back to a method call result
|
|
51
|
+
lhsKey = undefined;
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
// Simple path navigation — walk to parent, keep last key
|
|
55
|
+
if (pathParts.length === 0) {
|
|
56
|
+
lhsTarget = target;
|
|
57
|
+
} else if (pathParts.length === 1) {
|
|
58
|
+
lhsParent = target;
|
|
59
|
+
lhsKey = pathParts[0];
|
|
60
|
+
lhsTarget = target[pathParts[0]];
|
|
61
|
+
} else {
|
|
62
|
+
let current = target;
|
|
63
|
+
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
64
|
+
if (current == null) break;
|
|
65
|
+
current = current[pathParts[i]];
|
|
66
|
+
}
|
|
67
|
+
lhsParent = current;
|
|
68
|
+
lhsKey = pathParts[pathParts.length - 1];
|
|
69
|
+
lhsTarget = current != null ? current[lhsKey] : undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} else if (lhsPath) {
|
|
73
|
+
lhsParent = target;
|
|
74
|
+
lhsKey = lhsPath;
|
|
75
|
+
lhsTarget = target[lhsPath];
|
|
76
|
+
} else {
|
|
77
|
+
lhsTarget = target;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return { lhsTarget, lhsParent, lhsKey };
|
|
81
|
+
}
|
package/handlers/join.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* builtIns.join handler for assignFrom.
|
|
3
|
-
*
|
|
4
|
-
* Joins a resolved array into a single string. Supports nested sub-arrays
|
|
5
|
-
* with "all-or-nothing" semantics: if any element in a nested sub-array
|
|
6
|
-
* resolves to null/undefined, the entire sub-array is dropped.
|
|
7
|
-
*
|
|
8
|
-
* This handler is auto-loaded by processHandlerCommands when `do: 'builtIns.join'`
|
|
9
|
-
* is encountered — no explicit import is needed.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* assignFrom(oElement, {
|
|
13
|
-
* '?.textContent =>': {
|
|
14
|
-
* do: 'builtIns.join',
|
|
15
|
-
* resolve: {
|
|
16
|
-
* value: ['?.lastName', ', ', '?.firstName']
|
|
17
|
-
* }
|
|
18
|
-
* }
|
|
19
|
-
* }, { from: vm });
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* // With optional segment (all-or-nothing):
|
|
23
|
-
* assignFrom(oElement, {
|
|
24
|
-
* '?.textContent =>': {
|
|
25
|
-
* do: 'builtIns.join',
|
|
26
|
-
* resolve: {
|
|
27
|
-
* value: ['?.lastName', [', ', '?.middleName'], ', ', '?.firstName']
|
|
28
|
-
* }
|
|
29
|
-
* }
|
|
30
|
-
* }, { from: vm });
|
|
31
|
-
* // If middleName is undefined, the sub-array [', ', undefined] is dropped entirely.
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
import type { AssignFromHandler } from '../assignFromAsync.js';
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Process nested arrays with all-or-nothing null semantics.
|
|
38
|
-
* - Top-level null/undefined values are filtered out.
|
|
39
|
-
* - If a nested sub-array contains any null/undefined element, the entire sub-array is dropped.
|
|
40
|
-
* - Nested sub-arrays that pass are flattened into the result.
|
|
41
|
-
*/
|
|
42
|
-
function processValue(value: any[]): any[] {
|
|
43
|
-
const result: any[] = [];
|
|
44
|
-
for (const item of value) {
|
|
45
|
-
if (Array.isArray(item)) {
|
|
46
|
-
// All-or-nothing: if any element is null/undefined, drop the entire sub-array
|
|
47
|
-
if (item.some(el => el == null)) {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
// Sub-array passes — flatten its elements (recursively process nested arrays)
|
|
51
|
-
result.push(...processValue(item));
|
|
52
|
-
} else if (item != null) {
|
|
53
|
-
result.push(item);
|
|
54
|
-
}
|
|
55
|
-
// Top-level null/undefined are silently filtered out
|
|
56
|
-
}
|
|
57
|
-
return result;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* JoinHandler — built-in handler for composing strings from resolved arrays.
|
|
62
|
-
*
|
|
63
|
-
* Returns the joined string via the return-value protocol, which causes
|
|
64
|
-
* processHandlerCommands to assign it back to the LHS path.
|
|
65
|
-
*/
|
|
66
|
-
export class JoinHandler implements AssignFromHandler {
|
|
67
|
-
config: any;
|
|
68
|
-
|
|
69
|
-
constructor(config: any) {
|
|
70
|
-
this.config = config;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async assign(lhsTarget: any, resolvedParams: Record<string, any>): Promise<string> {
|
|
74
|
-
const { value, separator = '' } = resolvedParams;
|
|
75
|
-
|
|
76
|
-
const items = Array.isArray(value) ? processValue(value) : [value];
|
|
77
|
-
return items.join(separator);
|
|
78
|
-
}
|
|
79
|
-
}
|