assign-gingerly 0.0.71 → 0.0.73

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 (38) hide show
  1. package/DX/emojis.js +16 -0
  2. package/DX/emojis.ts +16 -0
  3. package/README.md +30 -3
  4. package/assignFrom.js +6 -6
  5. package/assignFrom.ts +11 -10
  6. package/assignFromAsync.js +3 -3
  7. package/assignFromAsync.ts +4 -4
  8. package/assignGingerly.js +136 -69
  9. package/assignGingerly.ts +170 -103
  10. package/assignPermissions/isAllowedImportPath.js +41 -0
  11. package/assignPermissions/isAllowedImportPath.ts +38 -0
  12. package/assignPermissions/restrictedProps.js +43 -0
  13. package/assignPermissions/restrictedProps.ts +53 -0
  14. package/assignTentatively.js +45 -30
  15. package/assignTentatively.ts +85 -60
  16. package/defineWithFeatures.js +38 -32
  17. package/defineWithFeatures.ts +46 -39
  18. package/eachTime.js +12 -4
  19. package/eachTime.ts +17 -7
  20. package/enhanceAll.js +2 -2
  21. package/enhanceAll.ts +3 -3
  22. package/evaluatePathWithAsyncMethods.js +29 -16
  23. package/evaluatePathWithAsyncMethods.ts +31 -16
  24. package/handlers/addEventListener.js +11 -11
  25. package/handlers/addEventListener.ts +18 -15
  26. package/handlers/lazyLoad.ts +10 -7
  27. package/handlers/lazyLoadSwitch.ts +4 -3
  28. package/handlers/manageTemplateList.js +9 -9
  29. package/handlers/manageTemplateList.ts +11 -10
  30. package/handlers/rangeSelector.ts +4 -3
  31. package/inferencer/types/assign-gingerly/types.d.ts +63 -4
  32. package/inferencer/types/nested-regex-groups/types.d.ts +12 -0
  33. package/package.json +6 -5
  34. package/processHandlerCommands.js +7 -4
  35. package/processHandlerCommands.ts +13 -10
  36. package/types/assign-gingerly/types.d.ts +63 -4
  37. package/isAllowedImportPath.js +0 -42
  38. package/isAllowedImportPath.ts +0 -53
package/eachTime.js CHANGED
@@ -3,6 +3,7 @@
3
3
  * This module is dynamically loaded only when @eachTime is encountered
4
4
  * Provides event-driven iteration over elements as they mount
5
5
  */
6
+ import { redirectRestrictedProp } from './assignPermissions/restrictedProps.js';
6
7
  /**
7
8
  * Check if a value is an EventTarget
8
9
  */
@@ -20,7 +21,7 @@ function isEventTarget(value) {
20
21
  * @param aliasMap - Map of aliases for token substitution
21
22
  * @param options - Options including required AbortSignal
22
23
  */
23
- export async function handleEachTime(target, pathParts, forEachIndex, value, withMethods, aliasMap, options) {
24
+ export async function handleEachTime(target, pathParts, forEachIndex, value, withMethods, aliasMap, options, permissions, restrictedPropSet) {
24
25
  // Validate signal - required for cleanup
25
26
  if (!options?.signal) {
26
27
  throw new Error('@eachTime requires an AbortSignal in options.signal for cleanup');
@@ -65,7 +66,11 @@ export async function handleEachTime(target, pathParts, forEachIndex, value, wit
65
66
  // Last segment is a method - call it
66
67
  const method = result.target[result.lastKey];
67
68
  if (typeof method === 'function') {
68
- if (Array.isArray(value)) {
69
+ if (result.isZeroArg) {
70
+ // Trailing | marker - call with no arguments, ignoring the value
71
+ method.call(result.target);
72
+ }
73
+ else if (Array.isArray(value)) {
69
74
  method.apply(result.target, value);
70
75
  }
71
76
  else {
@@ -77,7 +82,10 @@ export async function handleEachTime(target, pathParts, forEachIndex, value, wit
77
82
  // Normal assignment
78
83
  const lastKey = result.lastKey;
79
84
  const parent = result.target;
80
- if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
85
+ if (redirectRestrictedProp(restrictedPropSet, parent, lastKey, value)) {
86
+ // skip
87
+ }
88
+ else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
81
89
  // Check if property exists and is readonly
82
90
  if (lastKey in parent && isReadonlyProperty(parent, lastKey)) {
83
91
  const currentValue = parent[lastKey];
@@ -85,7 +93,7 @@ export async function handleEachTime(target, pathParts, forEachIndex, value, wit
85
93
  throw new Error(`Cannot merge object into readonly primitive property '${String(lastKey)}'`);
86
94
  }
87
95
  // Recursively apply assignGingerly
88
- assignGingerly(currentValue, value, options);
96
+ assignGingerly(currentValue, value, options, permissions);
89
97
  }
90
98
  else {
91
99
  // Property is writable - replace it
package/eachTime.ts CHANGED
@@ -4,7 +4,10 @@
4
4
  * Provides event-driven iteration over elements as they mount
5
5
  */
6
6
 
7
- import type { IAssignGingerlyOptions } from './types/assign-gingerly/types.js';
7
+ import type { IAssignGingerlyOptions } from './types/assign-gingerly/types.js';
8
+ import type { AssignPermissions } from './types/assign-gingerly/types.js';
9
+ import { redirectRestrictedProp } from './assignPermissions/restrictedProps.js';
10
+ import type { RestrictedPropSettingsMap } from './assignPermissions/restrictedProps.js';
8
11
 
9
12
  /**
10
13
  * Check if a value is an EventTarget
@@ -29,9 +32,11 @@ export async function handleEachTime(
29
32
  pathParts: string[],
30
33
  forEachIndex: number,
31
34
  value: any,
32
- withMethods: Set<string> | undefined,
33
- aliasMap: Map<string, string>,
34
- options?: IAssignGingerlyOptions
35
+ withMethods: Set<string> | undefined,
36
+ aliasMap: Map<string, string>,
37
+ options?: IAssignGingerlyOptions,
38
+ permissions?: AssignPermissions,
39
+ restrictedPropSet?: RestrictedPropSettingsMap
35
40
  ): Promise<void> {
36
41
  // Validate signal - required for cleanup
37
42
  if (!options?.signal) {
@@ -92,7 +97,10 @@ export async function handleEachTime(
92
97
  // Last segment is a method - call it
93
98
  const method = result.target[result.lastKey];
94
99
  if (typeof method === 'function') {
95
- if (Array.isArray(value)) {
100
+ if (result.isZeroArg) {
101
+ // Trailing | marker - call with no arguments, ignoring the value
102
+ method.call(result.target);
103
+ } else if (Array.isArray(value)) {
96
104
  method.apply(result.target, value);
97
105
  } else {
98
106
  method.call(result.target, value);
@@ -103,7 +111,9 @@ export async function handleEachTime(
103
111
  const lastKey = result.lastKey;
104
112
  const parent = result.target;
105
113
 
106
- if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
114
+ if (redirectRestrictedProp(restrictedPropSet, parent, lastKey, value)) {
115
+ // skip
116
+ } else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
107
117
  // Check if property exists and is readonly
108
118
  if (lastKey in parent && isReadonlyProperty(parent, lastKey)) {
109
119
  const currentValue = parent[lastKey];
@@ -113,7 +123,7 @@ export async function handleEachTime(
113
123
  );
114
124
  }
115
125
  // Recursively apply assignGingerly
116
- assignGingerly(currentValue, value, options);
126
+ assignGingerly(currentValue, value, options, permissions);
117
127
  } else {
118
128
  // Property is writable - replace it
119
129
  parent[lastKey] = value;
package/enhanceAll.js CHANGED
@@ -15,7 +15,7 @@
15
15
  * { emc: 'be-observant/emc.json', matching: '[itemprop]' },
16
16
  * ]);
17
17
  */
18
- import { isAllowedImportPath } from './isAllowedImportPath.js';
18
+ import { isAllowedImportPath } from './assignPermissions/isAllowedImportPath.js';
19
19
  /**
20
20
  * Apply enhancements in bulk to matching elements within a target.
21
21
  *
@@ -37,7 +37,7 @@ export async function enhanceAll(target, configs, permissions) {
37
37
  // Validate EMC path unless cross-domain imports are explicitly permitted
38
38
  if (!permissions?.crossDomainImports && !isAllowedImportPath(config.emc)) {
39
39
  throw new Error(`enhanceAll: EMC path "${config.emc}" is a cross-domain URL. ` +
40
- `Only relative, absolute, or bare specifier paths are allowed by default. ` +
40
+ `Only same-origin paths or import-map-covered specifiers are allowed by default. ` +
41
41
  `Pass { crossDomainImports: true } in permissions to override.`);
42
42
  }
43
43
  // 1. Import the EMC JSON
package/enhanceAll.ts CHANGED
@@ -16,8 +16,8 @@
16
16
  * ]);
17
17
  */
18
18
 
19
- import { isAllowedImportPath } from './isAllowedImportPath.js';
20
- import type { AssignPermissions } from './isAllowedImportPath.js';
19
+ import { isAllowedImportPath } from './assignPermissions/isAllowedImportPath.js';
20
+ import type { AssignPermissions } from './types/assign-gingerly/types.js';
21
21
 
22
22
  /**
23
23
  * Configuration for a single enhancement to apply in bulk.
@@ -57,7 +57,7 @@ export async function enhanceAll(
57
57
  if (!permissions?.crossDomainImports && !isAllowedImportPath(config.emc)) {
58
58
  throw new Error(
59
59
  `enhanceAll: EMC path "${config.emc}" is a cross-domain URL. ` +
60
- `Only relative, absolute, or bare specifier paths are allowed by default. ` +
60
+ `Only same-origin paths or import-map-covered specifiers are allowed by default. ` +
61
61
  `Pass { crossDomainImports: true } in permissions to override.`
62
62
  );
63
63
  }
@@ -28,12 +28,19 @@ export async function evaluatePathWithAsyncMethods(target, pathParts, value, wit
28
28
  while (i < pathParts.length - 1) {
29
29
  const part = pathParts[i];
30
30
  const nextPart = pathParts[i + 1];
31
- if (withAsyncMethods.has(part)) {
31
+ // A trailing | marks a zero-argument method call: 'deref|' calls deref()
32
+ // without consuming the next segment. Only applies to listed method names.
33
+ const isZeroArgSync = part.endsWith('|') && withMethods.has(part.slice(0, -1));
34
+ const isZeroArgAsync = part.endsWith('|') && withAsyncMethods.has(part.slice(0, -1));
35
+ const baseName = (isZeroArgSync || isZeroArgAsync) ? part.slice(0, -1) : part;
36
+ const nextIsMethod = withAsyncMethods.has(nextPart) || withMethods.has(nextPart)
37
+ || (nextPart.endsWith('|') && (withAsyncMethods.has(nextPart.slice(0, -1)) || withMethods.has(nextPart.slice(0, -1))));
38
+ if (withAsyncMethods.has(part) || isZeroArgAsync) {
32
39
  // Async method — call and await
33
- const method = current[part];
40
+ const method = current[baseName];
34
41
  if (typeof method === 'function') {
35
- if (withAsyncMethods.has(nextPart) || withMethods.has(nextPart)) {
36
- // Next is also a method call current with no args
42
+ if (isZeroArgAsync || nextIsMethod) {
43
+ // Zero-arg call — next is either a method or explicitly not an argument
37
44
  current = await method.call(current);
38
45
  }
39
46
  else {
@@ -44,18 +51,18 @@ export async function evaluatePathWithAsyncMethods(target, pathParts, value, wit
44
51
  }
45
52
  else {
46
53
  // Not a function — just access property
47
- if (current[part] === undefined || current[part] === null) {
48
- current[part] = {};
54
+ if (current[baseName] === undefined || current[baseName] === null) {
55
+ current[baseName] = {};
49
56
  }
50
- current = current[part];
57
+ current = current[baseName];
51
58
  }
52
59
  }
53
- else if (withMethods.has(part)) {
60
+ else if (withMethods.has(part) || isZeroArgSync) {
54
61
  // Sync method — same logic as evaluatePathWithMethods
55
- const method = current[part];
62
+ const method = current[baseName];
56
63
  if (typeof method === 'function') {
57
- if (withMethods.has(nextPart) || withAsyncMethods.has(nextPart)) {
58
- // Next is also a method call current with no args
64
+ if (isZeroArgSync || nextIsMethod) {
65
+ // Zero-arg call — next is either a method or explicitly not an argument
59
66
  current = method.call(current);
60
67
  }
61
68
  else {
@@ -65,10 +72,10 @@ export async function evaluatePathWithAsyncMethods(target, pathParts, value, wit
65
72
  }
66
73
  }
67
74
  else {
68
- if (!(part in current) || typeof current[part] !== 'object' || current[part] === null) {
69
- current[part] = {};
75
+ if (!(baseName in current) || typeof current[baseName] !== 'object' || current[baseName] === null) {
76
+ current[baseName] = {};
70
77
  }
71
- current = current[part];
78
+ current = current[baseName];
72
79
  }
73
80
  }
74
81
  else {
@@ -80,11 +87,17 @@ export async function evaluatePathWithAsyncMethods(target, pathParts, value, wit
80
87
  }
81
88
  i++;
82
89
  }
83
- const lastKey = pathParts[pathParts.length - 1];
90
+ // Strip a trailing | from the last segment only when it names a listed method;
91
+ // otherwise it is a literal property name (e.g. an exotic key ending in |).
92
+ const rawLastKey = pathParts[pathParts.length - 1];
93
+ const isZeroArg = rawLastKey.endsWith('|')
94
+ && (withMethods.has(rawLastKey.slice(0, -1)) || withAsyncMethods.has(rawLastKey.slice(0, -1)));
95
+ const lastKey = isZeroArg ? rawLastKey.slice(0, -1) : rawLastKey;
84
96
  return {
85
97
  target: current,
86
98
  lastKey,
87
99
  isMethod: withMethods.has(lastKey),
88
- isAsyncMethod: withAsyncMethods.has(lastKey)
100
+ isAsyncMethod: withAsyncMethods.has(lastKey),
101
+ isZeroArg
89
102
  };
90
103
  }
@@ -16,6 +16,7 @@ export interface AsyncPathResult {
16
16
  lastKey: string;
17
17
  isMethod: boolean;
18
18
  isAsyncMethod: boolean;
19
+ isZeroArg: boolean;
19
20
  }
20
21
 
21
22
  /**
@@ -44,12 +45,20 @@ export async function evaluatePathWithAsyncMethods(
44
45
  const part = pathParts[i];
45
46
  const nextPart = pathParts[i + 1];
46
47
 
47
- if (withAsyncMethods.has(part)) {
48
+ // A trailing | marks a zero-argument method call: 'deref|' calls deref()
49
+ // without consuming the next segment. Only applies to listed method names.
50
+ const isZeroArgSync = part.endsWith('|') && withMethods.has(part.slice(0, -1));
51
+ const isZeroArgAsync = part.endsWith('|') && withAsyncMethods.has(part.slice(0, -1));
52
+ const baseName = (isZeroArgSync || isZeroArgAsync) ? part.slice(0, -1) : part;
53
+ const nextIsMethod = withAsyncMethods.has(nextPart) || withMethods.has(nextPart)
54
+ || (nextPart.endsWith('|') && (withAsyncMethods.has(nextPart.slice(0, -1)) || withMethods.has(nextPart.slice(0, -1))));
55
+
56
+ if (withAsyncMethods.has(part) || isZeroArgAsync) {
48
57
  // Async method — call and await
49
- const method = current[part];
58
+ const method = current[baseName];
50
59
  if (typeof method === 'function') {
51
- if (withAsyncMethods.has(nextPart) || withMethods.has(nextPart)) {
52
- // Next is also a method call current with no args
60
+ if (isZeroArgAsync || nextIsMethod) {
61
+ // Zero-arg call — next is either a method or explicitly not an argument
53
62
  current = await method.call(current);
54
63
  } else {
55
64
  // Call with next part as string arg, then await
@@ -58,17 +67,17 @@ export async function evaluatePathWithAsyncMethods(
58
67
  }
59
68
  } else {
60
69
  // Not a function — just access property
61
- if (current[part] === undefined || current[part] === null) {
62
- current[part] = {};
70
+ if (current[baseName] === undefined || current[baseName] === null) {
71
+ current[baseName] = {};
63
72
  }
64
- current = current[part];
73
+ current = current[baseName];
65
74
  }
66
- } else if (withMethods.has(part)) {
75
+ } else if (withMethods.has(part) || isZeroArgSync) {
67
76
  // Sync method — same logic as evaluatePathWithMethods
68
- const method = current[part];
77
+ const method = current[baseName];
69
78
  if (typeof method === 'function') {
70
- if (withMethods.has(nextPart) || withAsyncMethods.has(nextPart)) {
71
- // Next is also a method call current with no args
79
+ if (isZeroArgSync || nextIsMethod) {
80
+ // Zero-arg call — next is either a method or explicitly not an argument
72
81
  current = method.call(current);
73
82
  } else {
74
83
  // Call with next part as string arg
@@ -76,10 +85,10 @@ export async function evaluatePathWithAsyncMethods(
76
85
  i++; // Skip next part since we consumed it as argument
77
86
  }
78
87
  } else {
79
- if (!(part in current) || typeof current[part] !== 'object' || current[part] === null) {
80
- current[part] = {};
88
+ if (!(baseName in current) || typeof current[baseName] !== 'object' || current[baseName] === null) {
89
+ current[baseName] = {};
81
90
  }
82
- current = current[part];
91
+ current = current[baseName];
83
92
  }
84
93
  } else {
85
94
  // Not a method — normal property access
@@ -92,11 +101,17 @@ export async function evaluatePathWithAsyncMethods(
92
101
  i++;
93
102
  }
94
103
 
95
- const lastKey = pathParts[pathParts.length - 1];
104
+ // Strip a trailing | from the last segment only when it names a listed method;
105
+ // otherwise it is a literal property name (e.g. an exotic key ending in |).
106
+ const rawLastKey = pathParts[pathParts.length - 1];
107
+ const isZeroArg = rawLastKey.endsWith('|')
108
+ && (withMethods.has(rawLastKey.slice(0, -1)) || withAsyncMethods.has(rawLastKey.slice(0, -1)));
109
+ const lastKey = isZeroArg ? rawLastKey.slice(0, -1) : rawLastKey;
96
110
  return {
97
111
  target: current,
98
112
  lastKey,
99
113
  isMethod: withMethods.has(lastKey),
100
- isAsyncMethod: withAsyncMethods.has(lastKey)
114
+ isAsyncMethod: withAsyncMethods.has(lastKey),
115
+ isZeroArg
101
116
  };
102
117
  }
@@ -37,7 +37,7 @@ function extractShorthand(config) {
37
37
  /**
38
38
  * Process a single AssignDispatchVector — execute all toTarget/toHost/toLHS assignments.
39
39
  */
40
- function processVector(vector, source, target, host, lhs, inheritedOptions, useAssignFrom) {
40
+ function processVector(vector, source, target, host, lhs, inheritedOptions, useAssignFrom, permissions) {
41
41
  const destinations = [
42
42
  { key: 'toTarget', dest: target },
43
43
  { key: 'toHost', dest: host },
@@ -50,11 +50,11 @@ function processVector(vector, source, target, host, lhs, inheritedOptions, useA
50
50
  if (useAssignFrom && source != null) {
51
51
  // Dynamic import assignFrom on demand (fire-and-forget context, already async)
52
52
  import('../assignFrom.js').then(({ assignFrom }) => {
53
- assignFrom(dest, pattern, { from: source, ...inheritedOptions, ...vector.withOptions });
53
+ assignFrom(dest, pattern, { from: source, ...inheritedOptions, ...vector.withOptions }, permissions);
54
54
  });
55
55
  }
56
56
  else {
57
- assignGingerly(dest, pattern, inheritedOptions);
57
+ assignGingerly(dest, pattern, inheritedOptions, permissions);
58
58
  }
59
59
  }
60
60
  // Handle shorthand (implicit toHost)
@@ -62,11 +62,11 @@ function processVector(vector, source, target, host, lhs, inheritedOptions, useA
62
62
  if (shorthand) {
63
63
  if (useAssignFrom && source != null) {
64
64
  import('../assignFrom.js').then(({ assignFrom }) => {
65
- assignFrom(host, shorthand, { from: source, ...inheritedOptions, ...vector.withOptions });
65
+ assignFrom(host, shorthand, { from: source, ...inheritedOptions, ...vector.withOptions }, permissions);
66
66
  });
67
67
  }
68
68
  else {
69
- assignGingerly(host, shorthand, inheritedOptions);
69
+ assignGingerly(host, shorthand, inheritedOptions, permissions);
70
70
  }
71
71
  }
72
72
  }
@@ -79,7 +79,7 @@ function processVector(vector, source, target, host, lhs, inheritedOptions, useA
79
79
  * @param host - The options.from (source/view model)
80
80
  * @param inheritedOptions - Parent assignFrom options (withMethods, aka, etc.)
81
81
  */
82
- export function attachEventListener(lhs, config, target, host, inheritedOptions) {
82
+ export function attachEventListener(lhs, config, target, host, inheritedOptions, permissions) {
83
83
  const { on: eventName, get: getConfig, fromLHS, fromHost, fromTarget, fromEvent, dispatch } = config;
84
84
  // Resolve get config values
85
85
  const { abortController, key, nudge, options: listenerOptions, stopPropagation, preventDefault, dispatch: getDispatch } = getConfig ?? {};
@@ -112,22 +112,22 @@ export function attachEventListener(lhs, config, target, host, inheritedOptions)
112
112
  if (preventDefault)
113
113
  event.preventDefault();
114
114
  // Static assignments (no from) — top-level toTarget/toHost/toLHS + shorthand
115
- processVector(config, null, target, host, lhs, inheritedOptions, false);
115
+ processVector(config, null, target, host, lhs, inheritedOptions, false, permissions);
116
116
  // fromLHS assignments
117
117
  if (fromLHS) {
118
- processVector(fromLHS, lhs, target, host, lhs, inheritedOptions, true);
118
+ processVector(fromLHS, lhs, target, host, lhs, inheritedOptions, true, permissions);
119
119
  }
120
120
  // fromHost assignments
121
121
  if (fromHost) {
122
- processVector(fromHost, host, target, host, lhs, inheritedOptions, true);
122
+ processVector(fromHost, host, target, host, lhs, inheritedOptions, true, permissions);
123
123
  }
124
124
  // fromTarget assignments
125
125
  if (fromTarget) {
126
- processVector(fromTarget, target, target, host, lhs, inheritedOptions, true);
126
+ processVector(fromTarget, target, target, host, lhs, inheritedOptions, true, permissions);
127
127
  }
128
128
  // fromEvent assignments
129
129
  if (fromEvent) {
130
- processVector(fromEvent, event, target, host, lhs, inheritedOptions, true);
130
+ processVector(fromEvent, event, target, host, lhs, inheritedOptions, true, permissions);
131
131
  }
132
132
  // Dispatch custom event if configured
133
133
  const dispatchConfig = dispatch || getDispatch;
@@ -7,8 +7,9 @@
7
7
  * Attaches an event listener that executes assign vectors on event fire.
8
8
  */
9
9
 
10
- import assignGingerly from '../assignGingerly.js';
11
- import type { AddEventListenerConfig, AssignDispatchVector } from '../types/assign-gingerly/types.js';
10
+ import assignGingerly from '../assignGingerly.js';
11
+ import type { AddEventListenerConfig, AssignDispatchVector } from '../types/assign-gingerly/types.js';
12
+ import type { AssignPermissions } from '../types/assign-gingerly/types.js';
12
13
 
13
14
  /**
14
15
  * WeakMap for dedup: Element → Map<key, AbortController>
@@ -48,9 +49,10 @@ function processVector(
48
49
  source: any,
49
50
  target: any,
50
51
  host: any,
51
- lhs: Element,
52
- inheritedOptions: any,
53
- useAssignFrom: boolean
52
+ lhs: Element,
53
+ inheritedOptions: any,
54
+ useAssignFrom: boolean,
55
+ permissions?: AssignPermissions
54
56
  ): void {
55
57
  const destinations = [
56
58
  { key: 'toTarget' as const, dest: target },
@@ -64,10 +66,10 @@ function processVector(
64
66
  if (useAssignFrom && source != null) {
65
67
  // Dynamic import assignFrom on demand (fire-and-forget context, already async)
66
68
  import('../assignFrom.js').then(({ assignFrom }) => {
67
- assignFrom(dest, pattern, { from: source, ...inheritedOptions, ...vector.withOptions });
69
+ assignFrom(dest, pattern, { from: source, ...inheritedOptions, ...vector.withOptions }, permissions);
68
70
  });
69
71
  } else {
70
- assignGingerly(dest, pattern, inheritedOptions);
72
+ assignGingerly(dest, pattern, inheritedOptions, permissions);
71
73
  }
72
74
  }
73
75
 
@@ -76,10 +78,10 @@ function processVector(
76
78
  if (shorthand) {
77
79
  if (useAssignFrom && source != null) {
78
80
  import('../assignFrom.js').then(({ assignFrom }) => {
79
- assignFrom(host, shorthand, { from: source, ...inheritedOptions, ...vector.withOptions });
81
+ assignFrom(host, shorthand, { from: source, ...inheritedOptions, ...vector.withOptions }, permissions);
80
82
  });
81
83
  } else {
82
- assignGingerly(host, shorthand, inheritedOptions);
84
+ assignGingerly(host, shorthand, inheritedOptions, permissions);
83
85
  }
84
86
  }
85
87
  }
@@ -98,7 +100,8 @@ export function attachEventListener(
98
100
  config: AddEventListenerConfig,
99
101
  target: any,
100
102
  host: any,
101
- inheritedOptions: any
103
+ inheritedOptions: any,
104
+ permissions?: AssignPermissions
102
105
  ): void {
103
106
  const { on: eventName, get: getConfig, fromLHS, fromHost, fromTarget, fromEvent, dispatch } = config;
104
107
 
@@ -131,26 +134,26 @@ export function attachEventListener(
131
134
  if (preventDefault) event.preventDefault();
132
135
 
133
136
  // Static assignments (no from) — top-level toTarget/toHost/toLHS + shorthand
134
- processVector(config, null, target, host, lhs, inheritedOptions, false);
137
+ processVector(config, null, target, host, lhs, inheritedOptions, false, permissions);
135
138
 
136
139
  // fromLHS assignments
137
140
  if (fromLHS) {
138
- processVector(fromLHS, lhs, target, host, lhs, inheritedOptions, true);
141
+ processVector(fromLHS, lhs, target, host, lhs, inheritedOptions, true, permissions);
139
142
  }
140
143
 
141
144
  // fromHost assignments
142
145
  if (fromHost) {
143
- processVector(fromHost, host, target, host, lhs, inheritedOptions, true);
146
+ processVector(fromHost, host, target, host, lhs, inheritedOptions, true, permissions);
144
147
  }
145
148
 
146
149
  // fromTarget assignments
147
150
  if (fromTarget) {
148
- processVector(fromTarget, target, target, host, lhs, inheritedOptions, true);
151
+ processVector(fromTarget, target, target, host, lhs, inheritedOptions, true, permissions);
149
152
  }
150
153
 
151
154
  // fromEvent assignments
152
155
  if (fromEvent) {
153
- processVector(fromEvent, event, target, host, lhs, inheritedOptions, true);
156
+ processVector(fromEvent, event, target, host, lhs, inheritedOptions, true, permissions);
154
157
  }
155
158
 
156
159
  // Dispatch custom event if configured
@@ -23,7 +23,8 @@ import type { AssignFromHandler } from '../assignFromAsync.js';
23
23
  import type { LazyLoadResolvedParams, LazyLoadInstantiatedContext } from '../types/assign-gingerly/types.js';
24
24
  import { withTransition, ensureHideStyle, DEFAULT_HIDE_CLASS } from '../transitionHelper.js';
25
25
  import { findMarkers, createMarkers, getNodesBetweenMarkers, findMarkersSibling, createMarkersSibling, MARKER_START_PREFIX, MARKER_END } from '../markerUtils.js';
26
- import { assignFrom } from '../assignFrom.js';
26
+ import { assignFrom } from '../assignFrom.js';
27
+ import type { AssignPermissions } from '../types/assign-gingerly/types.js';
27
28
 
28
29
  export type { LazyLoadResolvedParams, LazyLoadInstantiatedContext };
29
30
 
@@ -46,16 +47,18 @@ function getMarkerName(templateEl: any): string {
46
47
  * Exported so it can be subclassed for custom behavior.
47
48
  */
48
49
  export class LazyLoadHandler implements AssignFromHandler {
49
- config: any;
50
- _options: any;
50
+ config: any;
51
+ _options: any;
52
+ _permissions?: AssignPermissions;
51
53
  static #markerCounter = 0;
52
54
 
53
55
  constructor(config: any) {
54
56
  this.config = config;
55
57
  }
56
58
 
57
- async assign(lhsTarget: any, resolvedParams: LazyLoadResolvedParams, options?: any): Promise<void> {
58
- this._options = options; // Store for applyAssign access
59
+ async assign(lhsTarget: any, resolvedParams: LazyLoadResolvedParams, options?: any, permissions?: AssignPermissions): Promise<void> {
60
+ this._options = options; // Store for applyAssign access
61
+ this._permissions = permissions;
59
62
  const {
60
63
  if: condition,
61
64
  instantiate,
@@ -317,10 +320,10 @@ export class LazyLoadHandler implements AssignFromHandler {
317
320
  const len = Math.min(elements.length, assign.configs.length);
318
321
  for (let j = 0; j < len; j++) {
319
322
  const cfg = assign.configs[j];
320
- assignFrom(elements[j], cfg.toClone ?? {}, { from, ...cfg.withOptions });
323
+ assignFrom(elements[j], cfg.toClone ?? {}, { from, ...cfg.withOptions }, this._permissions);
321
324
  }
322
325
  } else if (assign.toClone) {
323
- assignFrom(elements[0], assign.toClone, { from, ...assign.withOptions });
326
+ assignFrom(elements[0], assign.toClone, { from, ...assign.withOptions }, this._permissions);
324
327
  }
325
328
  }
326
329
 
@@ -20,7 +20,8 @@
20
20
  * }, { withMethods: ['querySelector'], from: vm, protocols: { globalThis: k => globalThis[k] } });
21
21
  */
22
22
 
23
- import { LazyLoadHandler } from './lazyLoad.js';
23
+ import { LazyLoadHandler } from './lazyLoad.js';
24
+ import type { AssignPermissions } from '../types/assign-gingerly/types.js';
24
25
  import type { AssignFromHandler } from '../assignFromAsync.js';
25
26
  import type { LazyLoadSwitchResolvedParams } from '../types/assign-gingerly/types.js';
26
27
 
@@ -55,10 +56,10 @@ function evaluateOp(lhs: any, op: string, rhs: any): boolean {
55
56
  */
56
57
  export class LazyLoadSwitchHandler extends LazyLoadHandler implements AssignFromHandler {
57
58
 
58
- async assign(lhsTarget: any, resolvedParams: LazyLoadSwitchResolvedParams): Promise<void> {
59
+ async assign(lhsTarget: any, resolvedParams: LazyLoadSwitchResolvedParams, options?: any, permissions?: AssignPermissions): Promise<void> {
59
60
  const { lhs, op = '===', rhs, ...rest } = resolvedParams;
60
61
  const condition = evaluateOp(lhs, op, rhs);
61
62
  // Delegate to parent with computed condition
62
- return super.assign(lhsTarget, { ...rest, if: condition });
63
+ return super.assign(lhsTarget, { ...rest, if: condition }, options, permissions);
63
64
  }
64
65
  }
@@ -55,7 +55,7 @@ export class ManageTemplateListHandler {
55
55
  constructor(config) {
56
56
  this.config = config;
57
57
  }
58
- async assign(lhsTarget, resolvedParams, options) {
58
+ async assign(lhsTarget, resolvedParams, options, permissions) {
59
59
  //return;
60
60
  const { forEach: items, instantiate, method = 'appendChild', forget = false, markerName, yieldEvery, } = resolvedParams;
61
61
  if (!(lhsTarget instanceof Element)) {
@@ -143,7 +143,7 @@ export class ManageTemplateListHandler {
143
143
  const len = Math.min(elements.length, configs.length);
144
144
  for (let j = 0; j < len; j++) {
145
145
  const cfg = configs[j];
146
- assignFrom(elements[j], cfg.toClone ?? {}, { from: item, ...cfg.withOptions });
146
+ assignFrom(elements[j], cfg.toClone ?? {}, { from: item, ...cfg.withOptions }, permissions);
147
147
  }
148
148
  }
149
149
  else {
@@ -153,13 +153,13 @@ export class ManageTemplateListHandler {
153
153
  processInferred(rootEl, item, inferredConfig === true ? { byItemprop: true } : inferredConfig);
154
154
  }
155
155
  else {
156
- assignFrom(rootEl, toClone, { from: item, ...withOptions });
156
+ assignFrom(rootEl, toClone, { from: item, ...withOptions }, permissions);
157
157
  }
158
158
  if (hostToClone && options?.from) {
159
- assignFrom(rootEl, hostToClone, { from: options.from, ...hostWithOptions });
159
+ assignFrom(rootEl, hostToClone, { from: options.from, ...hostWithOptions }, permissions);
160
160
  }
161
161
  if (targetToClone) {
162
- assignFrom(rootEl, targetToClone, { from: lhsTarget, ...targetWithOptions });
162
+ assignFrom(rootEl, targetToClone, { from: lhsTarget, ...targetWithOptions }, permissions);
163
163
  }
164
164
  }
165
165
  }
@@ -192,7 +192,7 @@ export class ManageTemplateListHandler {
192
192
  const len = Math.min(elements.length, configs.length);
193
193
  for (let j = 0; j < len; j++) {
194
194
  const cfg = configs[j];
195
- assignFrom(elements[j], cfg.toClone ?? {}, { from: item, ...cfg.withOptions });
195
+ assignFrom(elements[j], cfg.toClone ?? {}, { from: item, ...cfg.withOptions }, permissions);
196
196
  }
197
197
  }
198
198
  else {
@@ -204,13 +204,13 @@ export class ManageTemplateListHandler {
204
204
  processInferred(rootEl, item, inferredConfig === true ? { byItemprop: true } : inferredConfig);
205
205
  }
206
206
  else {
207
- assignFrom(rootEl, toClone, { from: item, ...withOptions });
207
+ assignFrom(rootEl, toClone, { from: item, ...withOptions }, permissions);
208
208
  }
209
209
  if (hostToClone && options?.from) {
210
- assignFrom(rootEl, hostToClone, { from: options.from, ...hostWithOptions });
210
+ assignFrom(rootEl, hostToClone, { from: options.from, ...hostWithOptions }, permissions);
211
211
  }
212
212
  if (targetToClone) {
213
- assignFrom(rootEl, targetToClone, { from: lhsTarget, ...targetWithOptions });
213
+ assignFrom(rootEl, targetToClone, { from: lhsTarget, ...targetWithOptions }, permissions);
214
214
  }
215
215
  }
216
216
  }