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.
@@ -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
- }