assign-gingerly 0.0.79 → 0.0.81

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/assignGingerly.js CHANGED
@@ -420,6 +420,7 @@ export function isAllowedMethod(methodName, withMethods, permissionProcessor) {
420
420
  export function evaluatePathWithMethods(target, pathParts, value, withMethods, permissionProcessor) {
421
421
  let current = target;
422
422
  let i = 0;
423
+ let lastSegmentConsumed = false;
423
424
  // Process all segments except the last one
424
425
  while (i < pathParts.length - 1) {
425
426
  const part = pathParts[i];
@@ -442,6 +443,9 @@ export function evaluatePathWithMethods(target, pathParts, value, withMethods, p
442
443
  // Only current is method - call with next part as string arg
443
444
  current = method.call(current, nextPart, ...appendArgs);
444
445
  i++; // Skip next part since we consumed it as argument
446
+ if (i === pathParts.length - 1) {
447
+ lastSegmentConsumed = true;
448
+ }
445
449
  }
446
450
  }
447
451
  else {
@@ -470,7 +474,8 @@ export function evaluatePathWithMethods(target, pathParts, value, withMethods, p
470
474
  target: current,
471
475
  lastKey,
472
476
  isMethod: isAllowedMethod(lastKey, withMethods, permissionProcessor),
473
- isZeroArg
477
+ isZeroArg,
478
+ lastSegmentConsumed
474
479
  };
475
480
  }
476
481
  /**
@@ -623,6 +628,95 @@ function applyToEach(iterable, remainingPath, value, withMethods, aliasMap, opti
623
628
  }
624
629
  }
625
630
  }
631
+ /**
632
+ * Resolve the RHS of a toggle (=!) command to the value that should be negated.
633
+ * Supports:
634
+ * - '?.path' nested path strings resolved against target (returns the resolved value, or true if missing)
635
+ * - plain key strings looked up on target (returns the value, or true if missing)
636
+ * - resolved literal values (e.g., booleans from assignFrom) returned as-is
637
+ */
638
+ function resolveValueToNegate(rhsPath, target) {
639
+ if (typeof rhsPath === 'string' && isNestedPath(rhsPath)) {
640
+ const rhsPathParts = parsePath(rhsPath);
641
+ let current = target;
642
+ let exists = true;
643
+ for (const part of rhsPathParts) {
644
+ if (current && typeof current === 'object' && part in current) {
645
+ current = current[part];
646
+ }
647
+ else {
648
+ exists = false;
649
+ break;
650
+ }
651
+ }
652
+ return exists ? current : true;
653
+ }
654
+ if (typeof rhsPath === 'string') {
655
+ return (rhsPath in target) ? target[rhsPath] : true;
656
+ }
657
+ // Non-string resolved value (e.g., boolean, number, null from assignFrom)
658
+ return rhsPath;
659
+ }
660
+ /**
661
+ * Navigate a path that leads to an iterable, returning the iterable value or undefined.
662
+ * Handles withMethods and the evaluatePathWithMethods semantics.
663
+ */
664
+ function getIterableAtPath(target, pathParts, value, withMethods, permissionProcessor) {
665
+ let current = target;
666
+ if (pathParts.length > 0) {
667
+ if (withMethods && withMethods.size > 0) {
668
+ const result = evaluatePathWithMethods(target, pathParts, value, withMethods, permissionProcessor);
669
+ // evaluatePathWithMethods returns the container object + last key by default.
670
+ // If the last segment was consumed as a method argument, or the last segment
671
+ // is a zero-arg method marked with |, result.target is already the value.
672
+ if (result.lastSegmentConsumed) {
673
+ current = result.target;
674
+ }
675
+ else if (result.isMethod) {
676
+ const method = result.target[result.lastKey];
677
+ if (typeof method === 'function') {
678
+ const appendArgs = permissionProcessor?.getMethodAppendArgs(result.lastKey) ?? [];
679
+ current = method.call(result.target, ...appendArgs);
680
+ }
681
+ else {
682
+ current = method;
683
+ }
684
+ }
685
+ else {
686
+ current = result.target[result.lastKey];
687
+ }
688
+ }
689
+ else {
690
+ for (const part of pathParts) {
691
+ current = current[part];
692
+ }
693
+ }
694
+ }
695
+ return isIterable(current) ? current : undefined;
696
+ }
697
+ /**
698
+ * Apply an operator command (+=, =!, -=, Y=) to each item in an iterable.
699
+ * Detects @each in the path, navigates to the iterable, then builds a synthetic
700
+ * command key for the remaining path and delegates to assignGingerly per item.
701
+ * Nested @each is handled recursively through assignGingerly.
702
+ */
703
+ function applyCommandToEach(target, pathParts, commandSuffix, value, withMethods, aliasMap, options, permissionProcessor) {
704
+ const forEachIndex = pathParts.findIndex(part => isForEachSymbol(part, aliasMap));
705
+ if (forEachIndex === -1)
706
+ return;
707
+ const pathToForEach = pathParts.slice(0, forEachIndex);
708
+ const pathAfterForEach = pathParts.slice(forEachIndex + 1);
709
+ const iterable = getIterableAtPath(target, pathToForEach, value, withMethods, permissionProcessor);
710
+ if (!iterable)
711
+ return;
712
+ const items = Array.isArray(iterable) ? iterable : Array.from(iterable);
713
+ const syntheticKey = pathAfterForEach.length > 0
714
+ ? `?.${pathAfterForEach.join('?.')}${commandSuffix}`
715
+ : commandSuffix;
716
+ for (const item of items) {
717
+ assignGingerly(item, { [syntheticKey]: value }, options, permissionProcessor);
718
+ }
719
+ }
626
720
  /**
627
721
  * Apply alias substitutions to a key string.
628
722
  * Replaces complete tokens between `?.` delimiters with their aliased values.
@@ -727,6 +821,11 @@ export function assignGingerly(target, source, options, permissionProcessor) {
727
821
  if (path) {
728
822
  if (isNestedPath(path)) {
729
823
  const pathParts = parsePath(path);
824
+ // Check for @each in path
825
+ if (pathParts.some(part => isForEachSymbol(part, aliasMap))) {
826
+ applyCommandToEach(target, pathParts, ' +=', value, withMethodsSet, aliasMap, options, permissionProcessor);
827
+ continue;
828
+ }
730
829
  // Check for withMethods path evaluation
731
830
  let lhsValue;
732
831
  let lhsParent;
@@ -795,54 +894,47 @@ export function assignGingerly(target, source, options, permissionProcessor) {
795
894
  const lhsPath = parseToggleCommand(key);
796
895
  if (lhsPath) {
797
896
  const rhsPath = value;
798
- // Resolve LHS
799
- let lhsParent;
800
- let lhsLastKey;
801
897
  if (isNestedPath(lhsPath)) {
802
898
  const lhsPathParts = parsePath(lhsPath);
803
- lhsLastKey = lhsPathParts[lhsPathParts.length - 1];
804
- lhsParent = ensureNestedPath(target, lhsPathParts);
805
- }
806
- else {
807
- lhsLastKey = lhsPath;
808
- lhsParent = target;
809
- }
810
- // Determine what to negate
811
- let valueToNegate;
812
- if (rhsPath === '.') {
813
- // Self-reference: negate the LHS value itself (if it exists)
814
- if (lhsLastKey in lhsParent) {
815
- valueToNegate = lhsParent[lhsLastKey];
899
+ // Check for @each in the LHS path
900
+ if (lhsPathParts.some(part => isForEachSymbol(part, aliasMap))) {
901
+ // Resolve non-self-referencing RHS paths against the original target
902
+ // before iterating, so each item negates the same root value.
903
+ const resolvedValue = (rhsPath === '.' || typeof rhsPath !== 'string')
904
+ ? rhsPath
905
+ : resolveValueToNegate(rhsPath, target);
906
+ applyCommandToEach(target, lhsPathParts, ' =!', resolvedValue, withMethodsSet, aliasMap, options, permissionProcessor);
907
+ continue;
908
+ }
909
+ // No @each in path - standard toggle
910
+ const lhsLastKey = lhsPathParts[lhsPathParts.length - 1];
911
+ const lhsParent = ensureNestedPath(target, lhsPathParts);
912
+ // Determine what to negate
913
+ let valueToNegate;
914
+ if (rhsPath === '.') {
915
+ valueToNegate = (lhsLastKey in lhsParent) ? lhsParent[lhsLastKey] : undefined;
816
916
  }
817
917
  else {
818
- valueToNegate = undefined;
918
+ valueToNegate = resolveValueToNegate(rhsPath, target);
919
+ }
920
+ if (!permissionProcessor?.checkRestrictedProp(lhsLastKey)) {
921
+ lhsParent[lhsLastKey] = !valueToNegate;
819
922
  }
820
923
  }
821
924
  else {
822
- // RHS path: navigate to get the value (don't create paths)
823
- if (isNestedPath(rhsPath)) {
824
- const rhsPathParts = parsePath(rhsPath);
825
- let current = target;
826
- let exists = true;
827
- for (const part of rhsPathParts) {
828
- if (current && typeof current === 'object' && part in current) {
829
- current = current[part];
830
- }
831
- else {
832
- exists = false;
833
- break;
834
- }
835
- }
836
- valueToNegate = exists ? current : true;
925
+ // Plain key LHS
926
+ const lhsLastKey = lhsPath;
927
+ const lhsParent = target;
928
+ let valueToNegate;
929
+ if (rhsPath === '.') {
930
+ valueToNegate = (lhsLastKey in lhsParent) ? lhsParent[lhsLastKey] : undefined;
837
931
  }
838
932
  else {
839
- // Plain key RHS
840
- valueToNegate = (rhsPath in target) ? target[rhsPath] : true;
933
+ valueToNegate = resolveValueToNegate(rhsPath, target);
934
+ }
935
+ if (!permissionProcessor?.checkRestrictedProp(lhsLastKey)) {
936
+ lhsParent[lhsLastKey] = !valueToNegate;
841
937
  }
842
- }
843
- // Apply negation to LHS — check restriction first
844
- if (!permissionProcessor?.checkRestrictedProp(lhsLastKey)) {
845
- lhsParent[lhsLastKey] = !valueToNegate;
846
938
  }
847
939
  }
848
940
  continue;
@@ -856,6 +948,11 @@ export function assignGingerly(target, source, options, permissionProcessor) {
856
948
  let canDelete = true;
857
949
  if (isNestedPath(path)) {
858
950
  const pathParts = parsePath(path);
951
+ // Check for @each in path
952
+ if (pathParts.some(part => isForEachSymbol(part, aliasMap))) {
953
+ applyCommandToEach(target, pathParts, ' -=', value, withMethodsSet, aliasMap, options, permissionProcessor);
954
+ continue;
955
+ }
859
956
  if (pathParts.length === 0) {
860
957
  parent = target;
861
958
  }
@@ -901,6 +998,11 @@ export function assignGingerly(target, source, options, permissionProcessor) {
901
998
  if (permissionProcessor?.checkRestrictedProp(lastKey)) {
902
999
  continue;
903
1000
  }
1001
+ // Check for @each in path
1002
+ if (isNestedPath(path) && pathParts.some(part => isForEachSymbol(part, aliasMap))) {
1003
+ applyCommandToEach(target, pathParts, ' Y=', value, withMethodsSet, aliasMap, options, permissionProcessor);
1004
+ continue;
1005
+ }
904
1006
  // Navigate to the target sub-object
905
1007
  let mergeTarget;
906
1008
  if (isNestedPath(path)) {
@@ -956,22 +1058,9 @@ export function assignGingerly(target, source, options, permissionProcessor) {
956
1058
  const pathToForEach = pathParts.slice(0, forEachIndex);
957
1059
  const pathAfterForEach = pathParts.slice(forEachIndex + 1);
958
1060
  // Navigate to the iterable
959
- let current = target;
960
- if (pathToForEach.length > 0) {
961
- if (withMethodsSet) {
962
- const result = evaluatePathWithMethods(target, pathToForEach, value, withMethodsSet, permissionProcessor);
963
- // The result.target is the current position after evaluating the path
964
- // This is already the iterable we want
965
- current = result.target;
966
- }
967
- else {
968
- for (const part of pathToForEach) {
969
- current = current[part];
970
- }
971
- }
972
- }
1061
+ const current = getIterableAtPath(target, pathToForEach, value, withMethodsSet, permissionProcessor);
973
1062
  // Apply to each item in the iterable
974
- if (isIterable(current)) {
1063
+ if (current) {
975
1064
  applyToEach(current, pathAfterForEach, value, withMethodsSet || new Set(), aliasMap, options, permissionProcessor);
976
1065
  }
977
1066
  // If not iterable, let JavaScript throw error naturally when trying to iterate
package/assignGingerly.ts CHANGED
@@ -506,9 +506,10 @@ export function evaluatePathWithMethods(
506
506
  value: any,
507
507
  withMethods: Set<string>,
508
508
  permissionProcessor?: PermissionProcessor
509
- ): { target: any; lastKey: string; isMethod: boolean; isZeroArg: boolean } {
509
+ ): { target: any; lastKey: string; isMethod: boolean; isZeroArg: boolean; lastSegmentConsumed: boolean } {
510
510
  let current = target;
511
511
  let i = 0;
512
+ let lastSegmentConsumed = false;
512
513
 
513
514
  // Process all segments except the last one
514
515
  while (i < pathParts.length - 1) {
@@ -533,6 +534,9 @@ export function evaluatePathWithMethods(
533
534
  // Only current is method - call with next part as string arg
534
535
  current = method.call(current, nextPart, ...appendArgs);
535
536
  i++; // Skip next part since we consumed it as argument
537
+ if (i === pathParts.length - 1) {
538
+ lastSegmentConsumed = true;
539
+ }
536
540
  }
537
541
  } else {
538
542
  // Not a function - just access property (create if needed)
@@ -561,7 +565,8 @@ export function evaluatePathWithMethods(
561
565
  target: current,
562
566
  lastKey,
563
567
  isMethod: isAllowedMethod(lastKey, withMethods, permissionProcessor),
564
- isZeroArg
568
+ isZeroArg,
569
+ lastSegmentConsumed
565
570
  };
566
571
  }
567
572
 
@@ -724,6 +729,110 @@ function applyToEach(
724
729
  }
725
730
  }
726
731
 
732
+ /**
733
+ * Resolve the RHS of a toggle (=!) command to the value that should be negated.
734
+ * Supports:
735
+ * - '?.path' nested path strings resolved against target (returns the resolved value, or true if missing)
736
+ * - plain key strings looked up on target (returns the value, or true if missing)
737
+ * - resolved literal values (e.g., booleans from assignFrom) returned as-is
738
+ */
739
+ function resolveValueToNegate(rhsPath: any, target: any): any {
740
+ if (typeof rhsPath === 'string' && isNestedPath(rhsPath)) {
741
+ const rhsPathParts = parsePath(rhsPath);
742
+ let current = target;
743
+ let exists = true;
744
+ for (const part of rhsPathParts) {
745
+ if (current && typeof current === 'object' && part in current) {
746
+ current = current[part];
747
+ } else {
748
+ exists = false;
749
+ break;
750
+ }
751
+ }
752
+ return exists ? current : true;
753
+ }
754
+ if (typeof rhsPath === 'string') {
755
+ return (rhsPath in target) ? target[rhsPath] : true;
756
+ }
757
+ // Non-string resolved value (e.g., boolean, number, null from assignFrom)
758
+ return rhsPath;
759
+ }
760
+
761
+ /**
762
+ * Navigate a path that leads to an iterable, returning the iterable value or undefined.
763
+ * Handles withMethods and the evaluatePathWithMethods semantics.
764
+ */
765
+ function getIterableAtPath(
766
+ target: any,
767
+ pathParts: string[],
768
+ value: any,
769
+ withMethods: Set<string> | undefined,
770
+ permissionProcessor?: PermissionProcessor
771
+ ): any {
772
+ let current = target;
773
+ if (pathParts.length > 0) {
774
+ if (withMethods && withMethods.size > 0) {
775
+ const result = evaluatePathWithMethods(target, pathParts, value, withMethods, permissionProcessor);
776
+ // evaluatePathWithMethods returns the container object + last key by default.
777
+ // If the last segment was consumed as a method argument, or the last segment
778
+ // is a zero-arg method marked with |, result.target is already the value.
779
+ if (result.lastSegmentConsumed) {
780
+ current = result.target;
781
+ } else if (result.isMethod) {
782
+ const method = result.target[result.lastKey];
783
+ if (typeof method === 'function') {
784
+ const appendArgs = permissionProcessor?.getMethodAppendArgs(result.lastKey) ?? [];
785
+ current = method.call(result.target, ...appendArgs);
786
+ } else {
787
+ current = method;
788
+ }
789
+ } else {
790
+ current = result.target[result.lastKey];
791
+ }
792
+ } else {
793
+ for (const part of pathParts) {
794
+ current = current[part];
795
+ }
796
+ }
797
+ }
798
+ return isIterable(current) ? current : undefined;
799
+ }
800
+
801
+ /**
802
+ * Apply an operator command (+=, =!, -=, Y=) to each item in an iterable.
803
+ * Detects @each in the path, navigates to the iterable, then builds a synthetic
804
+ * command key for the remaining path and delegates to assignGingerly per item.
805
+ * Nested @each is handled recursively through assignGingerly.
806
+ */
807
+ function applyCommandToEach(
808
+ target: any,
809
+ pathParts: string[],
810
+ commandSuffix: string,
811
+ value: any,
812
+ withMethods: Set<string> | undefined,
813
+ aliasMap: Map<string, string>,
814
+ options?: IAssignGingerlyOptions,
815
+ permissionProcessor?: PermissionProcessor
816
+ ): void {
817
+ const forEachIndex = pathParts.findIndex(part => isForEachSymbol(part, aliasMap));
818
+ if (forEachIndex === -1) return;
819
+
820
+ const pathToForEach = pathParts.slice(0, forEachIndex);
821
+ const pathAfterForEach = pathParts.slice(forEachIndex + 1);
822
+
823
+ const iterable = getIterableAtPath(target, pathToForEach, value, withMethods, permissionProcessor);
824
+ if (!iterable) return;
825
+
826
+ const items = Array.isArray(iterable) ? iterable : Array.from(iterable);
827
+ const syntheticKey = pathAfterForEach.length > 0
828
+ ? `?.${pathAfterForEach.join('?.')}${commandSuffix}`
829
+ : commandSuffix;
830
+
831
+ for (const item of items) {
832
+ assignGingerly(item, { [syntheticKey]: value }, options, permissionProcessor);
833
+ }
834
+ }
835
+
727
836
  /**
728
837
  * Apply alias substitutions to a key string.
729
838
  * Replaces complete tokens between `?.` delimiters with their aliased values.
@@ -845,6 +954,12 @@ export function assignGingerly(
845
954
  if (isNestedPath(path)) {
846
955
  const pathParts = parsePath(path);
847
956
 
957
+ // Check for @each in path
958
+ if (pathParts.some(part => isForEachSymbol(part, aliasMap))) {
959
+ applyCommandToEach(target, pathParts, ' +=', value, withMethodsSet, aliasMap, options, permissionProcessor);
960
+ continue;
961
+ }
962
+
848
963
  // Check for withMethods path evaluation
849
964
  let lhsValue: any;
850
965
  let lhsParent: any;
@@ -915,52 +1030,51 @@ export function assignGingerly(
915
1030
  const lhsPath = parseToggleCommand(key);
916
1031
  if (lhsPath) {
917
1032
  const rhsPath = value;
918
-
919
- // Resolve LHS
920
- let lhsParent: any;
921
- let lhsLastKey: string;
1033
+
922
1034
  if (isNestedPath(lhsPath)) {
923
1035
  const lhsPathParts = parsePath(lhsPath);
924
- lhsLastKey = lhsPathParts[lhsPathParts.length - 1];
925
- lhsParent = ensureNestedPath(target, lhsPathParts);
926
- } else {
927
- lhsLastKey = lhsPath;
928
- lhsParent = target;
929
- }
930
1036
 
931
- // Determine what to negate
932
- let valueToNegate;
933
- if (rhsPath === '.') {
934
- // Self-reference: negate the LHS value itself (if it exists)
935
- if (lhsLastKey in lhsParent) {
936
- valueToNegate = lhsParent[lhsLastKey];
1037
+ // Check for @each in the LHS path
1038
+ if (lhsPathParts.some(part => isForEachSymbol(part, aliasMap))) {
1039
+ // Resolve non-self-referencing RHS paths against the original target
1040
+ // before iterating, so each item negates the same root value.
1041
+ const resolvedValue = (rhsPath === '.' || typeof rhsPath !== 'string')
1042
+ ? rhsPath
1043
+ : resolveValueToNegate(rhsPath, target);
1044
+ applyCommandToEach(target, lhsPathParts, ' =!', resolvedValue, withMethodsSet, aliasMap, options, permissionProcessor);
1045
+ continue;
1046
+ }
1047
+
1048
+ // No @each in path - standard toggle
1049
+ const lhsLastKey = lhsPathParts[lhsPathParts.length - 1];
1050
+ const lhsParent = ensureNestedPath(target, lhsPathParts);
1051
+
1052
+ // Determine what to negate
1053
+ let valueToNegate: any;
1054
+ if (rhsPath === '.') {
1055
+ valueToNegate = (lhsLastKey in lhsParent) ? lhsParent[lhsLastKey] : undefined;
937
1056
  } else {
938
- valueToNegate = undefined;
1057
+ valueToNegate = resolveValueToNegate(rhsPath, target);
1058
+ }
1059
+
1060
+ if (!permissionProcessor?.checkRestrictedProp(lhsLastKey)) {
1061
+ lhsParent[lhsLastKey] = !valueToNegate;
939
1062
  }
940
1063
  } else {
941
- // RHS path: navigate to get the value (don't create paths)
942
- if (isNestedPath(rhsPath)) {
943
- const rhsPathParts = parsePath(rhsPath);
944
- let current = target;
945
- let exists = true;
946
- for (const part of rhsPathParts) {
947
- if (current && typeof current === 'object' && part in current) {
948
- current = current[part];
949
- } else {
950
- exists = false;
951
- break;
952
- }
953
- }
954
- valueToNegate = exists ? current : true;
1064
+ // Plain key LHS
1065
+ const lhsLastKey = lhsPath;
1066
+ const lhsParent = target;
1067
+
1068
+ let valueToNegate: any;
1069
+ if (rhsPath === '.') {
1070
+ valueToNegate = (lhsLastKey in lhsParent) ? lhsParent[lhsLastKey] : undefined;
955
1071
  } else {
956
- // Plain key RHS
957
- valueToNegate = (rhsPath in target) ? target[rhsPath] : true;
1072
+ valueToNegate = resolveValueToNegate(rhsPath, target);
1073
+ }
1074
+
1075
+ if (!permissionProcessor?.checkRestrictedProp(lhsLastKey)) {
1076
+ lhsParent[lhsLastKey] = !valueToNegate;
958
1077
  }
959
- }
960
-
961
- // Apply negation to LHS — check restriction first
962
- if (!permissionProcessor?.checkRestrictedProp(lhsLastKey)) {
963
- lhsParent[lhsLastKey] = !valueToNegate;
964
1078
  }
965
1079
  }
966
1080
  continue;
@@ -976,6 +1090,13 @@ export function assignGingerly(
976
1090
 
977
1091
  if (isNestedPath(path)) {
978
1092
  const pathParts = parsePath(path);
1093
+
1094
+ // Check for @each in path
1095
+ if (pathParts.some(part => isForEachSymbol(part, aliasMap))) {
1096
+ applyCommandToEach(target, pathParts, ' -=', value, withMethodsSet, aliasMap, options, permissionProcessor);
1097
+ continue;
1098
+ }
1099
+
979
1100
  if (pathParts.length === 0) {
980
1101
  parent = target;
981
1102
  } else {
@@ -1019,6 +1140,13 @@ export function assignGingerly(
1019
1140
  if (permissionProcessor?.checkRestrictedProp(lastKey)) {
1020
1141
  continue;
1021
1142
  }
1143
+
1144
+ // Check for @each in path
1145
+ if (isNestedPath(path) && pathParts.some(part => isForEachSymbol(part, aliasMap))) {
1146
+ applyCommandToEach(target, pathParts, ' Y=', value, withMethodsSet, aliasMap, options, permissionProcessor);
1147
+ continue;
1148
+ }
1149
+
1022
1150
  // Navigate to the target sub-object
1023
1151
  let mergeTarget: any;
1024
1152
  if (isNestedPath(path)) {
@@ -1086,24 +1214,12 @@ export function assignGingerly(
1086
1214
  // Static forEach (@each) - existing logic
1087
1215
  const pathToForEach = pathParts.slice(0, forEachIndex);
1088
1216
  const pathAfterForEach = pathParts.slice(forEachIndex + 1);
1089
-
1217
+
1090
1218
  // Navigate to the iterable
1091
- let current = target;
1092
- if (pathToForEach.length > 0) {
1093
- if (withMethodsSet) {
1094
- const result = evaluatePathWithMethods(target, pathToForEach, value, withMethodsSet, permissionProcessor);
1095
- // The result.target is the current position after evaluating the path
1096
- // This is already the iterable we want
1097
- current = result.target;
1098
- } else {
1099
- for (const part of pathToForEach) {
1100
- current = current[part];
1101
- }
1102
- }
1103
- }
1104
-
1219
+ const current = getIterableAtPath(target, pathToForEach, value, withMethodsSet, permissionProcessor);
1220
+
1105
1221
  // Apply to each item in the iterable
1106
- if (isIterable(current)) {
1222
+ if (current) {
1107
1223
  applyToEach(current, pathAfterForEach, value, withMethodsSet || new Set(), aliasMap, options, permissionProcessor);
1108
1224
  }
1109
1225
  // If not iterable, let JavaScript throw error naturally when trying to iterate
@@ -47,7 +47,7 @@ async function defineIshProperty(element, managerName, options, assignGingerlyFn
47
47
  let config = registry.get(managerName);
48
48
  // If not registered, wait for registration
49
49
  if (!config) {
50
- const { waitForEvent } = await import('./waitForEvent.js');
50
+ const { waitForEvent } = await import('./utils/waitForEvent.js');
51
51
  await waitForEvent(registry, managerName);
52
52
  config = registry.get(managerName);
53
53
  if (!config) {
@@ -66,7 +66,7 @@ async function defineIshProperty(
66
66
 
67
67
  // If not registered, wait for registration
68
68
  if (!config) {
69
- const { waitForEvent } = await import('./waitForEvent.js');
69
+ const { waitForEvent } = await import('./utils/waitForEvent.js');
70
70
  await waitForEvent(registry, managerName);
71
71
  config = registry.get(managerName);
72
72
 
@@ -224,7 +224,7 @@ export class ManageTemplateListHandler {
224
224
  if (fragment.childNodes.length > 0) {
225
225
  const waitOpt = resolvedParams.waitForSettled;
226
226
  if (waitOpt) {
227
- const { waitForSettled } = await import('../waitForSettled.js');
227
+ const { waitForSettled } = await import('../utils/waitForSettled.js');
228
228
  const idleMs = typeof waitOpt === 'object' ? waitOpt.idleMs : 100;
229
229
  const timeout = typeof waitOpt === 'object' ? waitOpt.timeout : undefined;
230
230
  try {
@@ -263,7 +263,7 @@ export class ManageTemplateListHandler implements AssignFromHandler {
263
263
  if (fragment.childNodes.length > 0) {
264
264
  const waitOpt = resolvedParams.waitForSettled;
265
265
  if (waitOpt) {
266
- const { waitForSettled } = await import('../waitForSettled.js');
266
+ const { waitForSettled } = await import('../utils/waitForSettled.js');
267
267
  const idleMs = typeof waitOpt === 'object' ? waitOpt.idleMs : 100;
268
268
  const timeout = typeof waitOpt === 'object' ? waitOpt.timeout : undefined;
269
269
  try {
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export { assignGingerly } from './assignGingerly.js';
2
2
  export { assignTentatively } from './assignTentatively.js';
3
3
  export { EnhancementRegistry, ItemscopeRegistry, EnhancementRegisteredEvent } from './assignGingerly.js';
4
- export { waitForEvent } from './waitForEvent.js';
4
+ export { waitForEvent } from './utils/waitForEvent.js';
5
5
  export { ParserRegistry, globalParserRegistry } from './parserRegistry.js';
6
6
  export { parseWithAttrs } from './parseWithAttrs.js';
7
7
  export { buildCSSQuery } from './buildCSSQuery.js';
package/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export {assignGingerly} from './assignGingerly.js';
2
2
  export {assignTentatively} from './assignTentatively.js';
3
3
  export {EnhancementRegistry, ItemscopeRegistry, EnhancementRegisteredEvent} from './assignGingerly.js';
4
- export {waitForEvent} from './waitForEvent.js';
4
+ export {waitForEvent} from './utils/waitForEvent.js';
5
5
  export {ParserRegistry, globalParserRegistry} from './parserRegistry.js';
6
6
  export {parseWithAttrs} from './parseWithAttrs.js';
7
7
  export {buildCSSQuery} from './buildCSSQuery.js';