assign-gingerly 0.0.74 → 0.0.76

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.
Files changed (62) hide show
  1. package/DX/installForwarding.js +1 -1
  2. package/DX/installForwarding.ts +1 -1
  3. package/README.md +2 -0
  4. package/assignFrom.js +18 -17
  5. package/assignFrom.ts +23 -23
  6. package/assignFromAsync.js +14 -13
  7. package/assignFromAsync.ts +15 -15
  8. package/assignGingerly.js +46 -42
  9. package/assignGingerly.ts +131 -124
  10. package/assignPermissions/PermissionProcessor.js +166 -0
  11. package/assignPermissions/PermissionProcessor.ts +210 -0
  12. package/assignPermissions/isAllowedImportPath.js +2 -6
  13. package/assignPermissions/isAllowedImportPath.ts +3 -5
  14. package/assignPermissions/isAllowedUrl.js +18 -0
  15. package/assignPermissions/isAllowedUrl.ts +15 -0
  16. package/assignTentatively.js +9 -11
  17. package/assignTentatively.ts +11 -13
  18. package/beVigilant.js +1 -1
  19. package/beVigilant.ts +1 -1
  20. package/buildCSSQuery.js +1 -1
  21. package/buildCSSQuery.ts +1 -1
  22. package/eachTime.js +5 -6
  23. package/eachTime.ts +12 -15
  24. package/enhanceAll.js +3 -3
  25. package/enhanceAll.ts +4 -4
  26. package/evaluatePathWithAsyncMethods.js +12 -8
  27. package/evaluatePathWithAsyncMethods.ts +129 -117
  28. package/handlers/addEventListener.js +11 -11
  29. package/handlers/addEventListener.ts +12 -13
  30. package/handlers/lazyLoad.ts +7 -7
  31. package/handlers/lazyLoadSwitch.ts +3 -3
  32. package/handlers/manageTemplateList.js +10 -10
  33. package/handlers/manageTemplateList.ts +12 -12
  34. package/handlers/rangeSelector.ts +3 -3
  35. package/index.js +2 -3
  36. package/index.ts +2 -3
  37. package/inferencer/types/assign-gingerly/types.d.ts +37 -23
  38. package/inferencer/types/el-maker/types.d.ts +33 -0
  39. package/inferencer/types/scratch-box/types.d.ts +3 -0
  40. package/inferencer/types/truth-sourcer/types.d.ts +4 -0
  41. package/package.json +25 -23
  42. package/parseWithAttrs.js +1 -1
  43. package/parseWithAttrs.ts +1 -1
  44. package/processHandlerCommands.js +5 -7
  45. package/processHandlerCommands.ts +12 -15
  46. package/{getValues.js → resolve/getValues.js} +19 -8
  47. package/{getValues.ts → resolve/getValues.ts} +331 -314
  48. package/{resolveIdRef.js → resolve/resolveIdRef.js} +1 -1
  49. package/{resolveIdRef.ts → resolve/resolveIdRef.ts} +1 -1
  50. package/{resolveValues.ts → resolve/resolveValues.ts} +1 -1
  51. package/types/assign-gingerly/types.d.ts +37 -8
  52. package/utils/findClassPrototypeInPath.js +57 -0
  53. package/utils/findClassPrototypeInPath.ts +62 -0
  54. package/utils/isAsyncSpawn.js +20 -0
  55. package/utils/isAsyncSpawn.ts +17 -0
  56. package/assignPermissions/restrictedProps.js +0 -43
  57. package/assignPermissions/restrictedProps.ts +0 -53
  58. package/resolveAndAssignFeatures.js +0 -36
  59. package/resolveAndAssignFeatures.ts +0 -43
  60. /package/{resolveTemplate.js → resolve/resolveTemplate.js} +0 -0
  61. /package/{resolveTemplate.ts → resolve/resolveTemplate.ts} +0 -0
  62. /package/{resolveValues.js → resolve/resolveValues.js} +0 -0
package/assignGingerly.js CHANGED
@@ -1,5 +1,4 @@
1
- import { buildRestrictedPropSet, checkRestrictedProp, redirectRestrictedProp } from './assignPermissions/restrictedProps.js';
2
- import { normalizeAliasOptions } from './getValues.js';
1
+ import { normalizeAliasOptions } from './resolve/getValues.js';
3
2
  /**
4
3
  * GUID for global instance map storage to ensure uniqueness across package versions
5
4
  */
@@ -369,13 +368,21 @@ export function isClassInstance(value) {
369
368
  // Plain objects have Object.prototype or null as prototype
370
369
  return proto !== Object.prototype && proto !== null;
371
370
  }
371
+ /**
372
+ * Check whether a method name is listed in withMethods and is not restricted
373
+ * by the permission processor. Restricted methods are treated as non-method
374
+ * property names so they fall through to normal access.
375
+ */
376
+ export function isAllowedMethod(methodName, withMethods, permissionProcessor) {
377
+ return withMethods.has(methodName) && !permissionProcessor?.checkRestrictedMethod(methodName);
378
+ }
372
379
  /**
373
380
  * Helper function to evaluate a nested path with method calls
374
381
  * Handles chained method calls where path segments can be methods
375
382
  *
376
383
  * Exported for use by eachTime.ts
377
384
  */
378
- export function evaluatePathWithMethods(target, pathParts, value, withMethods) {
385
+ export function evaluatePathWithMethods(target, pathParts, value, withMethods, permissionProcessor) {
379
386
  let current = target;
380
387
  let i = 0;
381
388
  // Process all segments except the last one
@@ -384,10 +391,10 @@ export function evaluatePathWithMethods(target, pathParts, value, withMethods) {
384
391
  const nextPart = pathParts[i + 1];
385
392
  // A trailing | marks a zero-argument method call: 'deref|' calls deref()
386
393
  // without consuming the next segment. Only applies to names in withMethods.
387
- const isZeroArgMethod = part.endsWith('|') && withMethods.has(part.slice(0, -1));
394
+ const isZeroArgMethod = part.endsWith('|') && isAllowedMethod(part.slice(0, -1), withMethods, permissionProcessor);
388
395
  const nextIsMethod = withMethods.has(nextPart)
389
396
  || (nextPart.endsWith('|') && withMethods.has(nextPart.slice(0, -1)));
390
- if (withMethods.has(part) || isZeroArgMethod) {
397
+ if (isAllowedMethod(part, withMethods, permissionProcessor) || isZeroArgMethod) {
391
398
  const methodName = isZeroArgMethod ? part.slice(0, -1) : part;
392
399
  const method = current[methodName];
393
400
  if (typeof method === 'function') {
@@ -421,12 +428,12 @@ export function evaluatePathWithMethods(target, pathParts, value, withMethods) {
421
428
  // Strip a trailing | from the last segment only when it names a listed method;
422
429
  // otherwise it is a literal property name (e.g. an exotic key ending in |).
423
430
  const rawLastKey = pathParts[pathParts.length - 1];
424
- const isZeroArg = rawLastKey.endsWith('|') && withMethods.has(rawLastKey.slice(0, -1));
431
+ const isZeroArg = rawLastKey.endsWith('|') && isAllowedMethod(rawLastKey.slice(0, -1), withMethods, permissionProcessor);
425
432
  const lastKey = isZeroArg ? rawLastKey.slice(0, -1) : rawLastKey;
426
433
  return {
427
434
  target: current,
428
435
  lastKey,
429
- isMethod: withMethods.has(lastKey),
436
+ isMethod: isAllowedMethod(lastKey, withMethods, permissionProcessor),
430
437
  isZeroArg
431
438
  };
432
439
  }
@@ -474,7 +481,7 @@ function isReactiveForEachSymbol(segment, aliasMap) {
474
481
  /**
475
482
  * Apply a path to each item in an iterable
476
483
  */
477
- function applyToEach(iterable, remainingPath, value, withMethods, aliasMap, options, permissions, restrictedPropSet) {
484
+ function applyToEach(iterable, remainingPath, value, withMethods, aliasMap, options, permissionProcessor) {
478
485
  // Convert to array for iteration
479
486
  const items = Array.isArray(iterable) ? iterable : Array.from(iterable);
480
487
  // Apply the remaining path to each item
@@ -494,8 +501,8 @@ function applyToEach(iterable, remainingPath, value, withMethods, aliasMap, opti
494
501
  let current = item;
495
502
  for (const part of pathToForEach) {
496
503
  // A trailing | marks a zero-argument method call (only for names in withMethods)
497
- const isZeroArgMethod = part.endsWith('|') && withMethods.has(part.slice(0, -1));
498
- if (withMethods.has(part) || isZeroArgMethod) {
504
+ const isZeroArgMethod = part.endsWith('|') && isAllowedMethod(part.slice(0, -1), withMethods, permissionProcessor);
505
+ if (isAllowedMethod(part, withMethods, permissionProcessor) || isZeroArgMethod) {
499
506
  const methodName = isZeroArgMethod ? part.slice(0, -1) : part;
500
507
  const method = current[methodName];
501
508
  if (typeof method === 'function') {
@@ -530,12 +537,12 @@ function applyToEach(iterable, remainingPath, value, withMethods, aliasMap, opti
530
537
  }
531
538
  // Recursively apply to the nested iterable
532
539
  if (isIterable(current)) {
533
- applyToEach(current, pathAfterForEach, value, withMethods, aliasMap, options, permissions, restrictedPropSet);
540
+ applyToEach(current, pathAfterForEach, value, withMethods, aliasMap, options, permissionProcessor);
534
541
  }
535
542
  }
536
543
  else {
537
544
  // No nested @each, evaluate the remaining path normally
538
- const result = evaluatePathWithMethods(item, remainingPath, value, withMethods);
545
+ const result = evaluatePathWithMethods(item, remainingPath, value, withMethods, permissionProcessor);
539
546
  if (result.isMethod) {
540
547
  // Last segment is a method - call it
541
548
  const method = result.target[result.lastKey];
@@ -556,7 +563,7 @@ function applyToEach(iterable, remainingPath, value, withMethods, aliasMap, opti
556
563
  // Normal assignment
557
564
  const lastKey = result.lastKey;
558
565
  const parent = result.target;
559
- if (redirectRestrictedProp(restrictedPropSet, parent, lastKey, value)) {
566
+ if (permissionProcessor?.redirectRestrictedProp(parent, lastKey, value)) {
560
567
  // skip
561
568
  }
562
569
  else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
@@ -565,7 +572,7 @@ function applyToEach(iterable, remainingPath, value, withMethods, aliasMap, opti
565
572
  if (typeof currentValue !== 'object' || currentValue === null) {
566
573
  throw new Error(`Cannot merge object into readonly primitive property '${String(lastKey)}'`);
567
574
  }
568
- assignGingerly(currentValue, value, options, permissions);
575
+ assignGingerly(currentValue, value, options, permissionProcessor);
569
576
  }
570
577
  else {
571
578
  parent[lastKey] = value;
@@ -602,13 +609,11 @@ function applyAliases(key, aliasMap) {
602
609
  /**
603
610
  * Main assignGingerly function
604
611
  */
605
- export function assignGingerly(target, source, options, permissions) {
612
+ export function assignGingerly(target, source, options, permissionProcessor) {
606
613
  if (!target || typeof target !== 'object') {
607
614
  return target;
608
615
  }
609
616
  const { aliasMap, withMethods: withMethodsSet } = normalizeAliasOptions(options);
610
- // Normalize restrictedPropSettings once per top-level call
611
- const restrictedPropSet = buildRestrictedPropSet(permissions);
612
617
  // Convert withAsyncMethods array to Set for O(1) lookup
613
618
  const withAsyncMethodsSet = options?.withAsyncMethods
614
619
  ? options.withAsyncMethods instanceof Set
@@ -689,7 +694,7 @@ export function assignGingerly(target, source, options, permissions) {
689
694
  let lhsParent;
690
695
  let lhsKey;
691
696
  if (withMethodsSet) {
692
- const result = evaluatePathWithMethods(target, pathParts, value, withMethodsSet);
697
+ const result = evaluatePathWithMethods(target, pathParts, value, withMethodsSet, permissionProcessor);
693
698
  lhsParent = result.target;
694
699
  lhsKey = result.lastKey;
695
700
  lhsValue = lhsParent[lhsKey];
@@ -700,7 +705,7 @@ export function assignGingerly(target, source, options, permissions) {
700
705
  lhsValue = lhsParent[lhsKey];
701
706
  }
702
707
  //TODO: this logic seems to occur twice at least. Maybe make it a method?
703
- if (checkRestrictedProp(restrictedPropSet, lhsKey)) {
708
+ if (permissionProcessor?.checkRestrictedProp(lhsKey)) {
704
709
  continue;
705
710
  }
706
711
  // Event handler: Element LHS + object RHS with 'on' property
@@ -710,7 +715,7 @@ export function assignGingerly(target, source, options, permissions) {
710
715
  const capturedTarget = target;
711
716
  const capturedOptions = options;
712
717
  import('./handlers/addEventListener.js').then(({ attachEventListener }) => {
713
- attachEventListener(capturedLhs, capturedValue, capturedTarget, capturedOptions?.from ?? capturedTarget, capturedOptions ?? {}, permissions);
718
+ attachEventListener(capturedLhs, capturedValue, capturedTarget, capturedOptions?.from ?? capturedTarget, capturedOptions ?? {}, permissionProcessor);
714
719
  });
715
720
  continue;
716
721
  }
@@ -723,7 +728,7 @@ export function assignGingerly(target, source, options, permissions) {
723
728
  }
724
729
  else {
725
730
  // Plain key - direct operation on target
726
- if (checkRestrictedProp(restrictedPropSet, path)) {
731
+ if (permissionProcessor?.checkRestrictedProp(path)) {
727
732
  continue;
728
733
  }
729
734
  // Event handler: Element LHS + object RHS with 'on' property
@@ -733,7 +738,7 @@ export function assignGingerly(target, source, options, permissions) {
733
738
  const capturedTarget = target;
734
739
  const capturedOptions = options;
735
740
  import('./handlers/addEventListener.js').then(({ attachEventListener }) => {
736
- attachEventListener(capturedLhs, capturedValue, capturedTarget, capturedOptions?.from ?? capturedTarget, capturedOptions ?? {}, permissions);
741
+ attachEventListener(capturedLhs, capturedValue, capturedTarget, capturedOptions?.from ?? capturedTarget, capturedOptions ?? {}, permissionProcessor);
737
742
  });
738
743
  continue;
739
744
  }
@@ -798,7 +803,7 @@ export function assignGingerly(target, source, options, permissions) {
798
803
  }
799
804
  }
800
805
  // Apply negation to LHS — check restriction first
801
- if (!checkRestrictedProp(restrictedPropSet, lhsLastKey)) {
806
+ if (!permissionProcessor?.checkRestrictedProp(lhsLastKey)) {
802
807
  lhsParent[lhsLastKey] = !valueToNegate;
803
808
  }
804
809
  }
@@ -855,14 +860,14 @@ export function assignGingerly(target, source, options, permissions) {
855
860
  if (path) {
856
861
  const pathParts = isNestedPath(path) ? parsePath(path) : [path];
857
862
  const lastKey = pathParts[pathParts.length - 1];
858
- if (checkRestrictedProp(restrictedPropSet, lastKey)) {
863
+ if (permissionProcessor?.checkRestrictedProp(lastKey)) {
859
864
  continue;
860
865
  }
861
866
  // Navigate to the target sub-object
862
867
  let mergeTarget;
863
868
  if (isNestedPath(path)) {
864
869
  if (withMethodsSet) {
865
- const result = evaluatePathWithMethods(target, parsePath(path), value, withMethodsSet);
870
+ const result = evaluatePathWithMethods(target, parsePath(path), value, withMethodsSet, permissionProcessor);
866
871
  mergeTarget = result.target[result.lastKey];
867
872
  }
868
873
  else {
@@ -884,7 +889,7 @@ export function assignGingerly(target, source, options, permissions) {
884
889
  }
885
890
  // Recursively merge if target is a valid object
886
891
  if (mergeTarget && typeof mergeTarget === 'object') {
887
- assignGingerly(mergeTarget, value, options, permissions);
892
+ assignGingerly(mergeTarget, value, options, permissionProcessor);
888
893
  }
889
894
  }
890
895
  continue;
@@ -901,7 +906,7 @@ export function assignGingerly(target, source, options, permissions) {
901
906
  (async () => {
902
907
  try {
903
908
  const { handleEachTime } = await import('./eachTime.js');
904
- await handleEachTime(target, pathParts, forEachIndex, value, withMethodsSet, aliasMap, options, permissions, restrictedPropSet);
909
+ await handleEachTime(target, pathParts, forEachIndex, value, withMethodsSet, aliasMap, options, permissionProcessor);
905
910
  }
906
911
  catch (error) {
907
912
  console.error('Error in @eachTime:', error);
@@ -916,7 +921,7 @@ export function assignGingerly(target, source, options, permissions) {
916
921
  let current = target;
917
922
  if (pathToForEach.length > 0) {
918
923
  if (withMethodsSet) {
919
- const result = evaluatePathWithMethods(target, pathToForEach, value, withMethodsSet);
924
+ const result = evaluatePathWithMethods(target, pathToForEach, value, withMethodsSet, permissionProcessor);
920
925
  // The result.target is the current position after evaluating the path
921
926
  // This is already the iterable we want
922
927
  current = result.target;
@@ -929,7 +934,7 @@ export function assignGingerly(target, source, options, permissions) {
929
934
  }
930
935
  // Apply to each item in the iterable
931
936
  if (isIterable(current)) {
932
- applyToEach(current, pathAfterForEach, value, withMethodsSet || new Set(), aliasMap, options, permissions, restrictedPropSet);
937
+ applyToEach(current, pathAfterForEach, value, withMethodsSet || new Set(), aliasMap, options, permissionProcessor);
933
938
  }
934
939
  // If not iterable, let JavaScript throw error naturally when trying to iterate
935
940
  continue;
@@ -943,11 +948,10 @@ export function assignGingerly(target, source, options, permissions) {
943
948
  const capturedValue = value;
944
949
  const capturedWithMethodsSet = withMethodsSet || new Set();
945
950
  const capturedOptions = options;
946
- const capturedPermissions = permissions;
947
- const capturedRestrictedPropSet = restrictedPropSet;
951
+ const capturedPermissionProcessor = permissionProcessor;
948
952
  (async () => {
949
953
  const { evaluatePathWithAsyncMethods } = await import('./evaluatePathWithAsyncMethods.js');
950
- const result = await evaluatePathWithAsyncMethods(capturedTarget, capturedPathParts, capturedValue, capturedWithMethodsSet, withAsyncMethodsSet);
954
+ const result = await evaluatePathWithAsyncMethods(capturedTarget, capturedPathParts, capturedValue, capturedWithMethodsSet, withAsyncMethodsSet, capturedPermissionProcessor);
951
955
  if (result.isMethod || result.isAsyncMethod) {
952
956
  // Last segment is a method — call it
953
957
  const method = result.target[result.lastKey];
@@ -967,7 +971,7 @@ export function assignGingerly(target, source, options, permissions) {
967
971
  // Not a method — assign the value
968
972
  const lastKey = result.lastKey;
969
973
  const parent = result.target;
970
- if (redirectRestrictedProp(capturedRestrictedPropSet, parent, lastKey, capturedValue)) {
974
+ if (capturedPermissionProcessor?.redirectRestrictedProp(parent, lastKey, capturedValue)) {
971
975
  // skip
972
976
  }
973
977
  else if (typeof capturedValue === 'object' && capturedValue !== null && !Array.isArray(capturedValue)) {
@@ -976,7 +980,7 @@ export function assignGingerly(target, source, options, permissions) {
976
980
  if (typeof currentValue !== 'object' || currentValue === null) {
977
981
  throw new Error(`Cannot merge object into readonly primitive property '${String(lastKey)}'`);
978
982
  }
979
- assignGingerly(currentValue, capturedValue, capturedOptions, capturedPermissions);
983
+ assignGingerly(currentValue, capturedValue, capturedOptions, capturedPermissionProcessor);
980
984
  }
981
985
  else {
982
986
  parent[lastKey] = capturedValue;
@@ -991,7 +995,7 @@ export function assignGingerly(target, source, options, permissions) {
991
995
  }
992
996
  // Check if we need to handle methods
993
997
  if (withMethodsSet) {
994
- const result = evaluatePathWithMethods(target, pathParts, value, withMethodsSet);
998
+ const result = evaluatePathWithMethods(target, pathParts, value, withMethodsSet, permissionProcessor);
995
999
  if (result.isMethod) {
996
1000
  // Last segment is a method - call it
997
1001
  const method = result.target[result.lastKey];
@@ -1013,7 +1017,7 @@ export function assignGingerly(target, source, options, permissions) {
1013
1017
  // Not a method - proceed with normal assignment using evaluated target
1014
1018
  const lastKey = result.lastKey;
1015
1019
  const parent = result.target;
1016
- if (redirectRestrictedProp(restrictedPropSet, parent, lastKey, value)) {
1020
+ if (permissionProcessor?.redirectRestrictedProp(parent, lastKey, value)) {
1017
1021
  // skip
1018
1022
  // Check for static assignTo protocol
1019
1023
  }
@@ -1027,7 +1031,7 @@ export function assignGingerly(target, source, options, permissions) {
1027
1031
  if (typeof currentValue !== 'object' || currentValue === null) {
1028
1032
  throw new Error(`Cannot merge object into readonly primitive property '${String(lastKey)}'`);
1029
1033
  }
1030
- assignGingerly(currentValue, value, options, permissions);
1034
+ assignGingerly(currentValue, value, options, permissionProcessor);
1031
1035
  }
1032
1036
  else {
1033
1037
  // Property is writable - replace it
@@ -1042,7 +1046,7 @@ export function assignGingerly(target, source, options, permissions) {
1042
1046
  // No withMethods - use original logic
1043
1047
  const lastKey = pathParts[pathParts.length - 1];
1044
1048
  const parent = ensureNestedPath(target, pathParts);
1045
- if (redirectRestrictedProp(restrictedPropSet, parent, lastKey, value)) {
1049
+ if (permissionProcessor?.redirectRestrictedProp(parent, lastKey, value)) {
1046
1050
  // skip
1047
1051
  // Check for static assignTo protocol
1048
1052
  }
@@ -1058,7 +1062,7 @@ export function assignGingerly(target, source, options, permissions) {
1058
1062
  throw new Error(`Cannot merge object into readonly primitive property '${String(lastKey)}'`);
1059
1063
  }
1060
1064
  // Recursively apply assignGingerly to the readonly object
1061
- assignGingerly(currentValue, value, options, permissions);
1065
+ assignGingerly(currentValue, value, options, permissionProcessor);
1062
1066
  }
1063
1067
  else {
1064
1068
  // Property is writable - replace it
@@ -1092,7 +1096,7 @@ export function assignGingerly(target, source, options, permissions) {
1092
1096
  // Silently skip if not a function
1093
1097
  continue;
1094
1098
  }
1095
- if (redirectRestrictedProp(restrictedPropSet, target, key, value)) {
1099
+ if (permissionProcessor?.redirectRestrictedProp(target, key, value)) {
1096
1100
  // skip
1097
1101
  // Check for static assignTo protocol
1098
1102
  }
@@ -1108,7 +1112,7 @@ export function assignGingerly(target, source, options, permissions) {
1108
1112
  throw new Error(`Cannot merge object into readonly primitive property '${String(key)}'`);
1109
1113
  }
1110
1114
  // Recursively apply assignGingerly to the readonly object
1111
- assignGingerly(currentValue, value, options, permissions);
1115
+ assignGingerly(currentValue, value, options, permissionProcessor);
1112
1116
  }
1113
1117
  else {
1114
1118
  // Property is writable - replace it
@@ -1235,7 +1239,7 @@ export function assignGingerly(target, source, options, permissions) {
1235
1239
  // Fire-and-forget bulk enhancements (async, non-blocking)
1236
1240
  if (options?.enhance && options.enhance.length > 0 && typeof target === 'object' && target instanceof Element) {
1237
1241
  import('./enhanceAll.js').then(({ enhanceAll }) => {
1238
- enhanceAll(target, options.enhance, permissions);
1242
+ enhanceAll(target, options.enhance, permissionProcessor);
1239
1243
  });
1240
1244
  }
1241
1245
  return target;