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.
- 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 +11 -10
- package/assignFromAsync.js +3 -3
- package/assignFromAsync.ts +4 -4
- package/assignGingerly.js +136 -69
- package/assignGingerly.ts +170 -103
- package/assignPermissions/isAllowedImportPath.js +41 -0
- package/assignPermissions/isAllowedImportPath.ts +38 -0
- package/assignPermissions/restrictedProps.js +43 -0
- package/assignPermissions/restrictedProps.ts +53 -0
- 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 +17 -7
- package/enhanceAll.js +2 -2
- package/enhanceAll.ts +3 -3
- 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 +63 -4
- package/inferencer/types/nested-regex-groups/types.d.ts +12 -0
- package/package.json +6 -5
- package/processHandlerCommands.js +7 -4
- package/processHandlerCommands.ts +13 -10
- package/types/assign-gingerly/types.d.ts +63 -4
- package/isAllowedImportPath.js +0 -42
- 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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
|
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 './
|
|
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
|
|
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
|
-
|
|
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 '../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
|
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 '../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
|
}
|