assign-gingerly 0.0.71 → 0.0.72
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 +16 -0
- package/DX/emojis.ts +16 -0
- package/README.md +30 -3
- package/assignFrom.js +6 -6
- package/assignFrom.ts +10 -9
- package/assignFromAsync.js +3 -3
- package/assignFromAsync.ts +3 -3
- package/assignGingerly.js +136 -69
- package/assignGingerly.ts +169 -103
- package/assignTentatively.js +45 -30
- package/assignTentatively.ts +85 -60
- package/defineWithFeatures.js +38 -32
- package/defineWithFeatures.ts +46 -39
- package/eachTime.js +12 -4
- package/eachTime.ts +16 -7
- package/evaluatePathWithAsyncMethods.js +29 -16
- package/evaluatePathWithAsyncMethods.ts +31 -16
- package/handlers/addEventListener.js +11 -11
- package/handlers/addEventListener.ts +18 -15
- package/handlers/lazyLoad.ts +10 -7
- package/handlers/lazyLoadSwitch.ts +4 -3
- package/handlers/manageTemplateList.js +9 -9
- package/handlers/manageTemplateList.ts +11 -10
- package/handlers/rangeSelector.ts +4 -3
- package/inferencer/types/assign-gingerly/types.d.ts +60 -3
- package/isAllowedImportPath.js +62 -0
- package/isAllowedImportPath.ts +71 -6
- package/package.json +2 -2
- package/processHandlerCommands.js +5 -3
- package/processHandlerCommands.ts +10 -8
- package/types/assign-gingerly/types.d.ts +61 -4
package/eachTime.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
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, RestrictedPropSettingsMap } from './isAllowedImportPath.js';
|
|
9
|
+
import { redirectRestrictedProp } from './isAllowedImportPath.js';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Check if a value is an EventTarget
|
|
@@ -29,9 +31,11 @@ export async function handleEachTime(
|
|
|
29
31
|
pathParts: string[],
|
|
30
32
|
forEachIndex: number,
|
|
31
33
|
value: any,
|
|
32
|
-
withMethods: Set<string> | undefined,
|
|
33
|
-
aliasMap: Map<string, string>,
|
|
34
|
-
options?: IAssignGingerlyOptions
|
|
34
|
+
withMethods: Set<string> | undefined,
|
|
35
|
+
aliasMap: Map<string, string>,
|
|
36
|
+
options?: IAssignGingerlyOptions,
|
|
37
|
+
permissions?: AssignPermissions,
|
|
38
|
+
restrictedPropSet?: RestrictedPropSettingsMap
|
|
35
39
|
): Promise<void> {
|
|
36
40
|
// Validate signal - required for cleanup
|
|
37
41
|
if (!options?.signal) {
|
|
@@ -92,7 +96,10 @@ export async function handleEachTime(
|
|
|
92
96
|
// Last segment is a method - call it
|
|
93
97
|
const method = result.target[result.lastKey];
|
|
94
98
|
if (typeof method === 'function') {
|
|
95
|
-
if (
|
|
99
|
+
if (result.isZeroArg) {
|
|
100
|
+
// Trailing | marker - call with no arguments, ignoring the value
|
|
101
|
+
method.call(result.target);
|
|
102
|
+
} else if (Array.isArray(value)) {
|
|
96
103
|
method.apply(result.target, value);
|
|
97
104
|
} else {
|
|
98
105
|
method.call(result.target, value);
|
|
@@ -103,7 +110,9 @@ export async function handleEachTime(
|
|
|
103
110
|
const lastKey = result.lastKey;
|
|
104
111
|
const parent = result.target;
|
|
105
112
|
|
|
106
|
-
if (
|
|
113
|
+
if (redirectRestrictedProp(restrictedPropSet, parent, lastKey, value)) {
|
|
114
|
+
// skip
|
|
115
|
+
} else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
107
116
|
// Check if property exists and is readonly
|
|
108
117
|
if (lastKey in parent && isReadonlyProperty(parent, lastKey)) {
|
|
109
118
|
const currentValue = parent[lastKey];
|
|
@@ -113,7 +122,7 @@ export async function handleEachTime(
|
|
|
113
122
|
);
|
|
114
123
|
}
|
|
115
124
|
// Recursively apply assignGingerly
|
|
116
|
-
assignGingerly(currentValue, value, options);
|
|
125
|
+
assignGingerly(currentValue, value, options, permissions);
|
|
117
126
|
} else {
|
|
118
127
|
// Property is writable - replace it
|
|
119
128
|
parent[lastKey] = value;
|
|
@@ -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
|
-
|
|
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[
|
|
40
|
+
const method = current[baseName];
|
|
34
41
|
if (typeof method === 'function') {
|
|
35
|
-
if (
|
|
36
|
-
//
|
|
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[
|
|
48
|
-
current[
|
|
54
|
+
if (current[baseName] === undefined || current[baseName] === null) {
|
|
55
|
+
current[baseName] = {};
|
|
49
56
|
}
|
|
50
|
-
current = current[
|
|
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[
|
|
62
|
+
const method = current[baseName];
|
|
56
63
|
if (typeof method === 'function') {
|
|
57
|
-
if (
|
|
58
|
-
//
|
|
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 (!(
|
|
69
|
-
current[
|
|
75
|
+
if (!(baseName in current) || typeof current[baseName] !== 'object' || current[baseName] === null) {
|
|
76
|
+
current[baseName] = {};
|
|
70
77
|
}
|
|
71
|
-
current = current[
|
|
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
|
-
|
|
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
|
-
|
|
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[
|
|
58
|
+
const method = current[baseName];
|
|
50
59
|
if (typeof method === 'function') {
|
|
51
|
-
if (
|
|
52
|
-
//
|
|
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[
|
|
62
|
-
current[
|
|
70
|
+
if (current[baseName] === undefined || current[baseName] === null) {
|
|
71
|
+
current[baseName] = {};
|
|
63
72
|
}
|
|
64
|
-
current = current[
|
|
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[
|
|
77
|
+
const method = current[baseName];
|
|
69
78
|
if (typeof method === 'function') {
|
|
70
|
-
if (
|
|
71
|
-
//
|
|
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 (!(
|
|
80
|
-
current[
|
|
88
|
+
if (!(baseName in current) || typeof current[baseName] !== 'object' || current[baseName] === null) {
|
|
89
|
+
current[baseName] = {};
|
|
81
90
|
}
|
|
82
|
-
current = current[
|
|
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
|
-
|
|
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 '../isAllowedImportPath.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
|
package/handlers/lazyLoad.ts
CHANGED
|
@@ -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 '../isAllowedImportPath.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 '../isAllowedImportPath.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
|
}
|
|
@@ -30,7 +30,8 @@ import type { ManageTemplateListResolvedParams } from '../types/assign-gingerly/
|
|
|
30
30
|
import { findMarkers, createMarkers, getNodesBetweenMarkers, MARKER_START_PREFIX, MARKER_END } from '../markerUtils.js';
|
|
31
31
|
import { resolveValue } from '../resolveValues.js';
|
|
32
32
|
import { assignFrom } from '../assignFrom.js';
|
|
33
|
-
import { processInferredAssignments } from '../inferredAssignments.js';
|
|
33
|
+
import { processInferredAssignments } from '../inferredAssignments.js';
|
|
34
|
+
import type { AssignPermissions } from '../isAllowedImportPath.js';
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
37
|
* Reserved keys in fromEachItem config — not treated as shorthand patterns.
|
|
@@ -74,7 +75,7 @@ export class ManageTemplateListHandler implements AssignFromHandler {
|
|
|
74
75
|
this.config = config;
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
async assign(lhsTarget: any, resolvedParams: ManageTemplateListResolvedParams, options?: any): Promise<void> {
|
|
78
|
+
async assign(lhsTarget: any, resolvedParams: ManageTemplateListResolvedParams, options?: any, permissions?: AssignPermissions): Promise<void> {
|
|
78
79
|
//return;
|
|
79
80
|
const {
|
|
80
81
|
forEach: items,
|
|
@@ -183,7 +184,7 @@ export class ManageTemplateListHandler implements AssignFromHandler {
|
|
|
183
184
|
const len = Math.min(elements.length, configs.length);
|
|
184
185
|
for (let j = 0; j < len; j++) {
|
|
185
186
|
const cfg = configs[j];
|
|
186
|
-
assignFrom(elements[j], cfg.toClone ?? {}, { from: item, ...cfg.withOptions });
|
|
187
|
+
assignFrom(elements[j], cfg.toClone ?? {}, { from: item, ...cfg.withOptions }, permissions);
|
|
187
188
|
}
|
|
188
189
|
} else {
|
|
189
190
|
const rootEl = existingNodes.find(n => n instanceof Element) as Element | undefined;
|
|
@@ -191,13 +192,13 @@ export class ManageTemplateListHandler implements AssignFromHandler {
|
|
|
191
192
|
if (processInferred) {
|
|
192
193
|
processInferred(rootEl, item, inferredConfig === true ? { byItemprop: true } : inferredConfig);
|
|
193
194
|
} else {
|
|
194
|
-
assignFrom(rootEl, toClone, { from: item, ...withOptions });
|
|
195
|
+
assignFrom(rootEl, toClone, { from: item, ...withOptions }, permissions);
|
|
195
196
|
}
|
|
196
197
|
if (hostToClone && options?.from) {
|
|
197
|
-
assignFrom(rootEl, hostToClone, { from: options.from, ...hostWithOptions });
|
|
198
|
+
assignFrom(rootEl, hostToClone, { from: options.from, ...hostWithOptions }, permissions);
|
|
198
199
|
}
|
|
199
200
|
if (targetToClone) {
|
|
200
|
-
assignFrom(rootEl, targetToClone, { from: lhsTarget, ...targetWithOptions });
|
|
201
|
+
assignFrom(rootEl, targetToClone, { from: lhsTarget, ...targetWithOptions }, permissions);
|
|
201
202
|
}
|
|
202
203
|
}
|
|
203
204
|
}
|
|
@@ -228,7 +229,7 @@ export class ManageTemplateListHandler implements AssignFromHandler {
|
|
|
228
229
|
const len = Math.min(elements.length, configs.length);
|
|
229
230
|
for (let j = 0; j < len; j++) {
|
|
230
231
|
const cfg = configs[j];
|
|
231
|
-
assignFrom(elements[j], cfg.toClone ?? {}, { from: item, ...cfg.withOptions });
|
|
232
|
+
assignFrom(elements[j], cfg.toClone ?? {}, { from: item, ...cfg.withOptions }, permissions);
|
|
232
233
|
}
|
|
233
234
|
} else {
|
|
234
235
|
const rootEl = clonedNodes.find(n => n instanceof Element) as Element | undefined;
|
|
@@ -239,14 +240,14 @@ export class ManageTemplateListHandler implements AssignFromHandler {
|
|
|
239
240
|
if (processInferred) {
|
|
240
241
|
processInferred(rootEl, item, inferredConfig === true ? { byItemprop: true } : inferredConfig);
|
|
241
242
|
} else {
|
|
242
|
-
assignFrom(rootEl, toClone, { from: item, ...withOptions });
|
|
243
|
+
assignFrom(rootEl, toClone, { from: item, ...withOptions }, permissions);
|
|
243
244
|
}
|
|
244
245
|
|
|
245
246
|
if (hostToClone && options?.from) {
|
|
246
|
-
assignFrom(rootEl, hostToClone, { from: options.from, ...hostWithOptions });
|
|
247
|
+
assignFrom(rootEl, hostToClone, { from: options.from, ...hostWithOptions }, permissions);
|
|
247
248
|
}
|
|
248
249
|
if (targetToClone) {
|
|
249
|
-
assignFrom(rootEl, targetToClone, { from: lhsTarget, ...targetWithOptions });
|
|
250
|
+
assignFrom(rootEl, targetToClone, { from: lhsTarget, ...targetWithOptions }, permissions);
|
|
250
251
|
}
|
|
251
252
|
}
|
|
252
253
|
}
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import type { AssignFromHandler } from '../assignFromAsync.js';
|
|
25
|
-
import assignGingerly from '../assignGingerly.js';
|
|
25
|
+
import assignGingerly from '../assignGingerly.js';
|
|
26
|
+
import type { AssignPermissions } from '../isAllowedImportPath.js';
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Operator keys recognized in case objects.
|
|
@@ -72,7 +73,7 @@ export class RangeSelectorHandler implements AssignFromHandler {
|
|
|
72
73
|
this.config = config;
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
async assign(lhsTarget: any, resolvedParams: any): Promise<void> {
|
|
76
|
+
async assign(lhsTarget: any, resolvedParams: any, _options?: any, permissions?: AssignPermissions): Promise<void> {
|
|
76
77
|
const { value, when } = resolvedParams;
|
|
77
78
|
|
|
78
79
|
if (!Array.isArray(when)) return;
|
|
@@ -81,7 +82,7 @@ export class RangeSelectorHandler implements AssignFromHandler {
|
|
|
81
82
|
for (const caseObj of when) {
|
|
82
83
|
if (caseMatches(value, caseObj)) {
|
|
83
84
|
if (caseObj.merge && typeof caseObj.merge === 'object') {
|
|
84
|
-
assignGingerly(lhsTarget, caseObj.merge);
|
|
85
|
+
assignGingerly(lhsTarget, caseObj.merge, undefined, permissions);
|
|
85
86
|
}
|
|
86
87
|
return; // First match wins
|
|
87
88
|
}
|